home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / paint.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  79KB  |  3,715 lines

  1. /*
  2.  * $Id: paint.c,v 0.91 1994/02/23 02:27:14 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  *   Purpose:
  26.  *     To support standard paint functions.
  27.  *
  28.  *   All paint operators are based on a pen-plotter model, i.e.,  all
  29.  *   objects are done via
  30.  *
  31.  *    pen_init pen_down pen_move pen_up pen_motion pen_end pen_term
  32.  *
  33.  *   Three more functions are used to facilitate the utilization of
  34.  *   digital paint: pen_option, pen_outline and pen_redraw.
  35.  *
  36.  *   This model appears to be adquate and clean for all operations that I
  37.  *   want to implement.
  38.  */
  39.  
  40. #if !defined(lint) && defined(F_ID)
  41. char *id_pnt = "$Id: paint.c,v 0.91 1994/02/23 02:27:14 zhao Pre-Release $";
  42. #endif
  43.  
  44. #define PAINT_DRIVER        /* so paint.h loads static vars */
  45.  
  46. #include "bit.h"
  47. #include "extern.h"
  48. #include "paint.h"
  49. #include <math.h>
  50.  
  51. #ifndef M_PI
  52. #define M_PI   3.14159265358979323846
  53. #endif
  54.  
  55. /****************** Defines and Limits **************************/
  56.  
  57. #define MAX_LW      20        /* max. line width in pixels   */
  58. #define PAT_W       32        /* fill pattern width          */
  59. #define PAT_H       32        /* fill pattern height         */
  60. #define OP_COL      1        /* over_pup index used         */
  61. #define MAX_PNTS    2048    /* no. of pnts before flushing */
  62. #define LW_BM_COL   258        /* internal use for            */
  63.  
  64. /****************************************************************
  65.  * All paint tools operate on a "object" defined as Object_t, which
  66.  * could be thought as trace left behind if you move a pen
  67.  *****************************************************************/
  68.  
  69. typedef short Pnt_type;        /* point type */
  70. typedef struct
  71.   {
  72.       int n;            /* total points so far      */
  73.       int finished;        /* if ready to be "painted" */
  74.       Pnt_type x[MAX_PNTS], y[MAX_PNTS];
  75.   }
  76. Object_t;
  77.  
  78. static void
  79. shift_object(Object_t * obj, Pnt_type dx, Pnt_type dy)
  80. {
  81.     Pnt_type *x = obj->x, *y = obj->y, *xs = x + obj->n;
  82.  
  83.     while (x < xs)
  84.       {
  85.       *x += dx;
  86.       *y += dy;
  87.       x++;
  88.       y++;
  89.       }
  90. }
  91.  
  92. static Object_t cur_obj;
  93.  
  94. /* All pen command operates on the object defined by Object_t */
  95. typedef void (*pen_cmd_t) (Object_t *);
  96.  
  97. /* Description of a particular paint tools */
  98. typedef struct
  99.   {
  100.       pen_cmd_t pen_init;    /* get ready                   */
  101.       pen_cmd_t pen_down;    /* start tracing               */
  102.       pen_cmd_t pen_move;    /* motion while pen is down    */
  103.       pen_cmd_t pen_up;        /* end tracing                 */
  104.       pen_cmd_t pen_motion;    /* motion while pen is up      */
  105.       pen_cmd_t pen_end;    /* ready to be painted         */
  106.       pen_cmd_t pen_term;    /* clean up before tool change */
  107.       pen_cmd_t outline;    /* how to draw an outline      */
  108.       pen_cmd_t redraw;        /* transfer to canvas          */
  109.       void (*option) (void);    /* set tool specific options   */
  110.       int spray;        /* true if continous paint     */
  111.       int closed;        /* true if path is closed      */
  112.       int builtin;        /* true if redraw does meshing */
  113.   }
  114. Draw_t;
  115.  
  116. /**** and paint tool as shown *************************************/
  117. typedef struct
  118.   {
  119.       char *icons;        /* filename or bitmap             */
  120.       int bitmap;        /* true if icon contains bitmaps  */
  121.       Draw_t *(*make) (void);    /* install this tool              */
  122.       Draw_t *how;        /* set after make                 */
  123.   }
  124. PaintFunc;
  125.  
  126. /******************* Local varialbes ****************************/
  127.  
  128. static int cur_lw = 1;        /* line width. 0 for none       */
  129. static int cur_ls;        /* linw style                   */
  130. static int total_ls;        /* no. of built-ins. 0 solid    */
  131. static int cur_pat;        /* pattern. 0 solid.            */
  132. static int ccol[4];        /* current pattern color        */
  133. static int lcol[4];        /* current outline color        */
  134. static Draw_t *pdraw;        /* current drawing functions    */
  135.  
  136. static pen_cmd_t pen_move;    /* current tool tracing         */
  137.  
  138. /******************** Local functions ****************************/
  139.  
  140. static void paint_leftmouse(long);
  141. static void paint_middlemouse(long);
  142. static void paint_keybd(int);
  143. static int paint_init(IPTR, int);
  144. static int get_current_point(Object_t *);
  145. static void paint_finish(void);
  146. static int init_line_style(void);
  147.  
  148. static FL_FORM *fpaint;
  149. static FL_FORM *create_form_fpaint(void);
  150.  
  151. static void
  152. set_line_attribute(void)
  153. {
  154.     setlinestyle(cur_ls);
  155.     linewidth(cur_lw);
  156. }
  157.  
  158. static void
  159. reset_line_attribute(void)
  160. {
  161.     setlinestyle(0);
  162.     linewidth(1);
  163. }
  164.  
  165. /*********************************************************************
  166.  * Global entry point to paint function
  167.  **********************************************************************/
  168.  
  169. int
  170. img_paint(IPTR im)
  171. {
  172.     short val;
  173.     long dev;
  174.  
  175.     /*
  176.      * unlike other bit functions, we create an image on the fly if no image
  177.      * is loaded
  178.      */
  179.  
  180.     if (!im || !im->ok)
  181.       {
  182.       imgptr = im = create_image("", T_RGBA, 640, 480, 0x00ffffff);
  183.       imgptr->io->display(imgptr, 0, 0);
  184.       }
  185.  
  186.     /* currently, we only handle 24bits images */
  187.  
  188.     if (!IS_RGBA(im))
  189.       {
  190.       val = img_convert_type(im, T_RGBA);
  191.       M_info("Paint", "Converting to RGB %sOK", val ? "not " : "");
  192.       im->io->display(im, 0, 0);
  193.       }
  194.  
  195.     /*
  196.      * initialize paint system and install window manager's resize and
  197.      * reposition events
  198.      */
  199.     paint_init(im, 0);
  200.     install_wm_handler(paint_init);
  201.  
  202.     bit_show_form(create_form_fpaint(), FL_PLACE_POSITION, 0, "Paint");
  203.  
  204.     /* Looping until ESC key or done button is pressed */
  205.     while ((dev = bit_qread(&val)) != KEYBD || val != 27)
  206.       {
  207.       switch (dev)
  208.         {
  209.         case LEFTMOUSE:
  210.         if (val)
  211.             paint_leftmouse(dev);
  212.         break;
  213.  
  214.         case MENUBUTTON:
  215.         if (val && pdraw->option)
  216.             pdraw->option();
  217.         break;
  218.  
  219.         case MIDDLEMOUSE:
  220.         if (val)
  221.             paint_middlemouse(dev);
  222.         break;
  223.  
  224.         case KEYBD:
  225.         paint_keybd(val);
  226.         break;
  227.  
  228.         case UPARROWKEY:
  229.         if (val)
  230.             paint_keybd('k');
  231.         break;
  232.  
  233.         case DOWNARROWKEY:
  234.         if (val)
  235.             paint_keybd('j');
  236.         break;
  237.  
  238.         case LEFTARROWKEY:
  239.         if (val)
  240.             paint_keybd('h');
  241.         break;
  242.  
  243.         case RIGHTARROWKEY:
  244.         if (val)
  245.             paint_keybd('l');
  246.         break;
  247.         }
  248.  
  249.       /*
  250.        * get_point reports current mouse location if it is different from
  251.        * where we were last time
  252.        */
  253.       if (get_current_point(&cur_obj) && pdraw->pen_motion)
  254.         {
  255.         set_current_window(win_id);
  256.         switch_frame_buffer();
  257.         set_line_attribute();
  258.         pdraw->pen_motion(&cur_obj);
  259.         reset_line_attribute();
  260.         drawmode(NORMALDRAW);
  261.         }
  262.       }
  263.  
  264.     /* close main control panel */
  265.     bit_hide_form(create_form_fpaint());
  266.  
  267.     remove_wm_handler(paint_init);
  268.  
  269.     /* flush last object */
  270.     if (pdraw->pen_term)
  271.     pdraw->pen_term(&cur_obj);
  272.  
  273.     /* restore some graphics pipeline & bit default */
  274.     paint_finish();
  275.  
  276.     return 0;
  277. }
  278.  
  279. /*****************************************************************
  280.  * Under some paint tools, the standard way of handling the repaint
  281.  * is not adquate or need execessive buffering, the paint tool
  282.  * lets the driver know its traces by adding a "segment" which
  283.  * driver will take care of at the end of a paint job
  284.  ****************************************************************/
  285.  
  286. static int nseg;        /* no. ot segs so far */
  287. static Rect_t segments[MAX_PNTS];
  288.  
  289. /* add one segment */
  290. static void
  291. add_segment(int x, int y, int dx, int dy)
  292. {
  293.     Rect_t *s = segments + nseg++;
  294.     s->x = x;
  295.     s->y = y;
  296.     s->w = dx;
  297.     s->h = dy;
  298. }
  299.  
  300. /********************************************************************
  301.  * Without background rendering support, any rasterization via
  302.  * framebuffer read may not work due to stuff on top of the image.
  303.  *******************************************************************/
  304. static void ray_end(Object_t *);
  305.  
  306. static void
  307. paint_rasterize(Object_t * obj, Rect_t * s)
  308. {
  309.     int i;
  310.  
  311.     /*
  312.      * ray is a special case in that although it is not closed, the only way
  313.      * to get it rasterize correctly is to use the complete bound
  314.      */
  315.  
  316.     if (pdraw->closed || pdraw->pen_end == ray_end)
  317.       {
  318.       s = spoly_bounds(obj->x, obj->y, obj->n);
  319.       inc_rect(s, 2 * cur_lw + 1, 2 * cur_lw + 1);
  320.       shift_rect(s, -cur_lw, -cur_lw);
  321.       fb_to_ras(imgptr, s);
  322.       }
  323.     else
  324.       {
  325.       if (obj->n > 30)
  326.           show_busy("");
  327.  
  328.       /*
  329.        * have to do framebuffer read piecewise, otherwise, too many
  330.        * garbage falls into the bounds
  331.        */
  332.  
  333.       for (i = 0; i < obj->n - 1; i++)
  334.         {
  335.         s = spoly_bounds((obj->x) + i, (obj->y) + i, 2);
  336.         inc_rect(s, 2 * cur_lw + 1, 2 * cur_lw + 1);
  337.         shift_rect(s, -cur_lw, -cur_lw);
  338.         fb_to_ras(imgptr, s);
  339.         }
  340.  
  341.       if (obj->n > 30)
  342.           end_busy();
  343.       }
  344. }
  345.  
  346. /* how to handle it */
  347. static void
  348. handle_segments(Object_t * obj)
  349. {
  350.     Rect_t *s = segments, *ss = s + nseg;
  351.  
  352.     if (nseg)
  353.       {
  354.  
  355.       M_info("HandleSeg", "n=%d", nseg);
  356.       while (--ss >= s)
  357.           fb_to_ras(imgptr, ss);
  358.       }
  359.     else
  360.       {
  361.       paint_rasterize(obj, s);
  362.       }
  363.  
  364.     /* always reset */
  365.     nseg = 0;
  366. }
  367.  
  368. /******************************************************************
  369.  * Find out where we are and if moved, report current location
  370.  *****************************************************************/
  371.  
  372. static int
  373. get_current_point(Object_t * obj)
  374. {
  375.     int x, y, n = obj->n;
  376.     static int ox, oy;
  377.     int moved;
  378.  
  379.     get_mouse(&x, &y);
  380.     x -= win_xo;
  381.     y -= win_yo;
  382.  
  383.     obj->x[n] = x;
  384.     obj->y[n] = y;
  385.  
  386.     /* report mouse location only if moved */
  387.     if ((moved = (ox != x || oy != y)))
  388.     show_mouse_position(x, y);
  389.  
  390.     ox = x;
  391.     oy = y;
  392.  
  393.     return moved;
  394. }
  395.  
  396. /*** Definations for paint tools as known by the driver *********/
  397.  
  398. static Draw_t *make_fpoly(void);
  399. static Draw_t *make_pencil(void);
  400. static Draw_t *make_line(void);
  401. static Draw_t *make_circ(void);
  402. static Draw_t *make_ray(void);
  403. static Draw_t *make_erasor(void);
  404. static Draw_t *make_brush(void);
  405. static Draw_t *make_sqr(void);
  406. static Draw_t *make_default(void);
  407. static Draw_t *make_spray(void);
  408. static Draw_t *make_obj3d(void);
  409. static Draw_t *make_arc(void);
  410. static Draw_t *make_fill(void);
  411. static Draw_t *make_cut_paste(void);
  412. static Draw_t *make_import(void);
  413.  
  414. static PaintFunc paintfunc[] =
  415. {
  416.     {"pen.icon", 0, make_pencil},
  417.     {"brush.icon", 0, make_brush},
  418.     {"fill.icon", 0, make_fill},
  419.     {"spray.icon", 0, make_spray},
  420.     {"erasor.icon", 0, make_erasor},
  421.     {"cut.icon", 0, make_cut_paste},
  422.     {"obj3d.icon", 0, make_obj3d},
  423.     {line_bits, 1, make_line},
  424.     {fpoly_bits, 1, make_fpoly},
  425.     {circ_bits, 1, make_circ},
  426.     {arc_bits, 1, make_arc},
  427.     {rec_bits, 1, make_sqr},
  428.     {ray_bits, 1, make_ray}
  429. };
  430.  
  431. static int npaintfunc = sizeof(paintfunc) / sizeof(paintfunc[0]);
  432.  
  433. static void
  434. set_fill_pattern(void)
  435. {
  436.     linewidth(cur_lw);
  437.     setlinestyle(cur_ls);
  438.     setpattern(cur_pat);
  439.  
  440.     /*
  441.      * issue mesh command only if we know the draw command itself does not
  442.      * issue its own. Otherwise mess up the graphics pipeline badly
  443.      */
  444.  
  445.     if (!pdraw->builtin)
  446.       {
  447.       (!pdraw->closed ? bgnline :
  448.        (cur_pat != PAT_HOLLOW ? bgnpolygon : bgnclosedline)) ();
  449.       }
  450. }
  451.  
  452. static void
  453. reset_fill_pattern(void)
  454. {
  455.     if (!pdraw->builtin)
  456.       {
  457.       (!pdraw->closed ? endline :
  458.        (cur_pat != PAT_HOLLOW ? endpolygon : endclosedline)) ();
  459.       }
  460.     setpattern(0);
  461.     setlinestyle(0);
  462.     linewidth(1);
  463. }
  464.  
  465. static short svc[3];        /* original overlay  color         */
  466. static oldm_report;        /* copy of gloabl mouse report opt */
  467. static IPTR saved;        /* back up copy of image for undo  */
  468.  
  469. static int
  470. paint_init(IPTR im, int wme)
  471. {
  472.     static int lxi, lyi;
  473.  
  474.     if (wme > 0)
  475.       {
  476.       long od;
  477.  
  478.       /*
  479.        * figure out how much image has moved as a result of window
  480.        * manager's resize/reposition
  481.        */
  482.  
  483.       shift_object(&cur_obj, im->xi - lxi, im->yi - lyi);
  484.  
  485.  
  486.       clear_over_pup();
  487.       /* get current active framebuffer */
  488.       set_current_window(win_id);
  489.       od = getdrawmode();
  490. #if 1
  491.       switch_frame_buffer();
  492.       set_line_attribute();
  493.       color(OP_COL);
  494.       if (cur_obj.n > 0 && pdraw->redraw)
  495.         {
  496.         if (!pdraw->builtin)
  497.             bgnline();
  498.         pdraw->redraw(&cur_obj);
  499.         if (!pdraw->builtin)
  500.             endline();
  501.         }
  502.  
  503.       set_line_attribute();
  504. #else
  505.       draw_it(&cur_obj);
  506. #endif
  507.       /*
  508.        * need to shift the backup copy as well as erasor refers to its
  509.        * location
  510.        */
  511.       if (saved && saved->ok)
  512.         {
  513.         saved->xi = im->xi;
  514.         saved->yi = im->yi;
  515.         saved->xf = im->xf;
  516.         saved->yf = im->yf;
  517.         }
  518.  
  519.       /* restore active framebuffer */
  520.       drawmode(od);
  521.       }
  522.     else
  523.       {
  524.       create_form_fpaint();
  525.       oldm_report = report_mouse;
  526.       report_mouse = 1;
  527.       saved = img_dup(im);
  528.  
  529.       /*
  530.        * must initialize the lcol[3] to something that is not large than
  531.        * im->cmap->colors
  532.        */
  533.       if (IS_CI(im))
  534.         {
  535.         lcol[3] = ccol[3] = 0;
  536.         lcol[0] = ccol[0] = im->cmap->ct[0][ccol[3]];
  537.         lcol[1] = ccol[1] = im->cmap->ct[1][ccol[3]];
  538.         lcol[2] = ccol[2] = im->cmap->ct[2][ccol[3]];
  539.         }
  540.  
  541.       set_current_window(win_id);
  542.  
  543.       /* initialize paint tool specific stuff */
  544.  
  545.       if (pdraw && pdraw->pen_init)
  546.           pdraw->pen_init(&cur_obj);
  547.  
  548.       fl_mapcolor(LW_BM_COL, lcol[0], lcol[1], lcol[2]);
  549.       switch_frame_buffer();
  550.       getmcolor(OP_COL, svc, svc + 1, svc + 2);
  551.       mapcolor(OP_COL, ccol[0], ccol[1], ccol[2]);
  552.       drawmode(NORMALDRAW);
  553.  
  554.       /*
  555.        * although point sampled polygone looks better, can't use it as
  556.        * other parts of the program assumes oldpolygon
  557.        */
  558.  
  559.       glcompat(GLC_OLDPOLYGON, 1);
  560.  
  561.       /*
  562.        * pay a little performance penelty to get free hand polygon
  563.        * rendered correctly on PI, Indgoes and maybe others
  564.        */
  565.  
  566.       concave(1);
  567.       total_ls = init_line_style();
  568.       cur_obj.n = cur_obj.finished = 0;
  569.       }
  570.  
  571.     lxi = im->xi;
  572.     lyi = im->yi;
  573.  
  574.     return 0;
  575. }
  576.  
  577. /********************************************************************
  578.  * Finish up and restore all defaults
  579.  ********************************************************************/
  580. static void
  581. paint_finish(void)
  582. {
  583.     report_mouse = oldm_report;
  584.     op_mapcolor(OP_COL, svc[0], svc[1], svc[2]);
  585.  
  586.     if (pdraw->pen_end)
  587.     pdraw->pen_end(&cur_obj);
  588.  
  589.     drawmode(NORMALDRAW);
  590.  
  591.     /*
  592.      * there are several places 1pixel wide rectangle might be used, must let
  593.      * GL do outline to be correct
  594.      */
  595.     glcompat(GLC_OLDPOLYGON, 1);
  596.  
  597.     /* restore all graphics pineline default */
  598.     concave(0);
  599.     linewidth(1);
  600.     setlinestyle(0);
  601.     setpattern(0);
  602.  
  603.     clear_over_pup();
  604.     free_image(saved);
  605.     saved = 0;
  606.     rubber_finish();
  607. }
  608.  
  609. static int changed;        /* true if image's been altered */
  610.  
  611. /****************************************************************
  612.  * Replace saved copy with current image
  613.  ****************************************************************/
  614. static void
  615. paint_update(void)
  616. {
  617.     if (changed)
  618.       {
  619.       free_image(saved);
  620.       saved = img_dup(imgptr);
  621.       changed = 0;
  622.       }
  623. }
  624.  
  625. /*****************************************************************
  626.  * Restore saved copy
  627.  *****************************************************************/
  628. static void
  629. paint_undo(void)
  630. {
  631.     if (changed)
  632.       {
  633.       free_image(imgptr);
  634.       imgptr = img_dup(saved);
  635.       imgptr->io->display(imgptr, 0, 1);
  636.       changed = 0;
  637.       }
  638.  
  639. }
  640.  
  641. /***********************************************************************
  642.  * Actual rendering
  643.  ***********************************************************************/
  644. static void
  645. draw_it(Object_t * obj)
  646. {
  647.     int outline_only;
  648.  
  649.     Color4(ccol);
  650.     set_fill_pattern();
  651.     smooth_line_on(imgptr, ccol, cur_lw);
  652.     pdraw->redraw(obj);
  653.     reset_fill_pattern();
  654.     smooth_line_off(imgptr, ccol);
  655.  
  656.     /*
  657.      * draw outlines unless the area is not closed or current outline option
  658.      * is none, indicated by line width <= 0. Further if current pattern is
  659.      * none and area is closed, the outline IS the stuff we want, swap colors
  660.      */
  661.  
  662.     outline_only = (pdraw->closed && cur_pat == PAT_HOLLOW && pdraw->outline);
  663.  
  664.     if (outline_only || (pdraw->outline && cur_lw > 0))
  665.       {
  666.       int *cc = outline_only ? ccol : lcol;
  667.  
  668.       set_line_attribute();    /* need to go before smooth_line */
  669.       smooth_line_on(imgptr, cc, cur_lw);
  670.  
  671.       if (!pdraw->builtin)
  672.           bgnclosedline();
  673.  
  674.       pdraw->outline(obj);
  675.  
  676.       if (!pdraw->builtin)
  677.           endclosedline();
  678.  
  679.       reset_line_attribute();
  680.       smooth_line_off(imgptr, cc);
  681.       }
  682. }
  683.  
  684. /********************************************************************
  685.  * Regenerate traces and optionally render it into core mem via
  686.  * framebuffer read
  687.  ********************************************************************/
  688. static void
  689. paint_it(Object_t * obj)
  690. {
  691.     if (obj->n && obj->finished)
  692.       {
  693.  
  694.       set_current_window(win_id);
  695.       drawmode(NORMALDRAW);
  696.       reshapeviewport();
  697.  
  698.       draw_it(obj);
  699.  
  700.       if (double_buf)
  701.         {
  702.         swapbuffers();
  703.         draw_it(obj);
  704.         }
  705.  
  706.       handle_segments(obj);
  707.       changed = 1;
  708.       clear_over_pup();
  709.       }
  710.  
  711.     /*
  712.      * must reset current object and graphics pipe default regardless if we
  713.      * have drawn anything or not
  714.      */
  715.     obj->n = obj->finished = 0;
  716. }
  717.  
  718. /******************************************************************
  719.  * Due to hardware constraints (at most 256 vertex), we need to
  720.  * to divide objects into several pieces. This function is typicall
  721.  * called from within a pen_move
  722.  *****************************************************************/
  723. static void
  724. flush_object(Object_t * obj)
  725. {
  726.     int n = obj->n;
  727.     long odraw;
  728.     Pnt_type *x = obj->x, *y = obj->y;
  729.  
  730.     M_info("FlushObj", "at n=%d", n);
  731.  
  732.     set_current_window(win_id);
  733.     odraw = getdrawmode();
  734.  
  735.     obj->finished = 1;
  736.     paint_it(obj);
  737.  
  738.     /*
  739.      * paint_it has reset obj->n == 0, need to keep last two points for
  740.      * bootstrap
  741.      */
  742.     x[0] = x[n - 1];
  743.     y[0] = y[n - 1];
  744.     pdraw->pen_down(obj);
  745.     x[1] = x[n];
  746.     y[1] = y[n];
  747.     obj->n = 1;
  748.     pdraw->pen_move(obj);
  749.     drawmode(odraw);
  750. }
  751.  
  752. /* ARGSUSED */
  753. static void
  754. null_op(Object_t * ob)
  755. {
  756.     M_info("NullOP", "");
  757. }
  758.  
  759. /*******************************************************************
  760.  * Leftmouse: the pen down function.
  761.  * Paint tool by default leaves marks only if we move it. Spray
  762.  * is the only exception where marks accumlates
  763.  *******************************************************************/
  764.  
  765. static void
  766. paint_leftmouse(long dev)
  767. {
  768.     get_current_point(&cur_obj);
  769.  
  770.     set_current_window(win_id);
  771.     switch_frame_buffer();
  772.     set_line_attribute();
  773.  
  774.     if (pdraw->pen_down)
  775.     pdraw->pen_down(&cur_obj);
  776.  
  777.     while (getbutton(dev))
  778.       {
  779.       if (get_current_point(&cur_obj) || pdraw->spray)
  780.           pen_move(&cur_obj);
  781.  
  782.       /*
  783.        * if buffer is exhausted, paint the current object and start over
  784.        */
  785.       if (cur_obj.n >= MAX_PNTS - 1)
  786.           flush_object(&cur_obj);
  787.  
  788.       }
  789.     drawmode(NORMALDRAW);
  790.  
  791.     /* "pen" is up */
  792.     if (pdraw->pen_up)
  793.     pdraw->pen_up(&cur_obj);
  794.     reset_line_attribute();
  795. }
  796.  
  797. /* ARGSUSED */
  798. static void
  799. paint_middlemouse(long dev)
  800. {
  801.     if (pdraw->pen_end)
  802.     pdraw->pen_end(&cur_obj);
  803. }
  804.  
  805. /** handle keyboard event **/
  806. static void
  807. paint_keybd(int val)
  808. {
  809.     int n = cur_obj.n;
  810.     static int step = 1;
  811.     int moved = 1;
  812.  
  813.     if (!pdraw->pen_motion)
  814.     return;
  815.  
  816.     switch (val)
  817.       {
  818.       case 'j':
  819.       cur_obj.y[n] -= step;
  820.       break;
  821.       case 'h':
  822.       cur_obj.x[n] -= step;
  823.       break;
  824.       case 'k':
  825.       cur_obj.y[n] += step;
  826.       break;
  827.       case 'l':
  828.       cur_obj.x[n] += step;
  829.       break;
  830.       default:
  831.       moved = 0;
  832.       if (val > '0' && val <= '9')
  833.           step = val - '0';
  834.       break;
  835.       }
  836.  
  837.     /* warp mouse to new location and handle this manual motion */
  838.     if (moved)
  839.     set_mouse(cur_obj.x[n] + win_xo, cur_obj.y[n] + win_yo);
  840. }
  841.  
  842. /********************************************************************
  843.  *
  844.  * DEFINATION of all paint functions
  845.  *
  846.  ******************************************************************{*/
  847.  
  848. /*************** Line *****************************{**/
  849. static void
  850. line_redraw(Object_t * obj)
  851. {
  852.     draw_line(obj->x[0], obj->y[0], obj->x[1], obj->y[1]);
  853. }
  854.  
  855. static void
  856. line_end(Object_t * obj)
  857. {
  858.     obj->finished = obj->n > 0;
  859.     obj->n = 2;
  860.     paint_it(obj);
  861. }
  862.  
  863. static int ln_oldx, ln_oldy;
  864.  
  865. static void
  866. line_down(Object_t * obj)
  867. {
  868.     /* pen down */
  869.     if (obj->n == 0)
  870.       {
  871.       obj->n = 1;
  872.       ln_oldx = obj->x[0];
  873.       ln_oldy = obj->y[0];
  874.       return;
  875.       }
  876.  
  877.     /* 2nd time around */
  878.     line_end(obj);
  879. }
  880.  
  881. static void
  882. line_motion(Object_t * obj)
  883. {
  884.     Pnt_type *x = obj->x, *y = obj->y;
  885.  
  886.     if (obj->n == 0)
  887.     return;
  888.  
  889.     /* show size and theta, among other things */
  890.     show_rect_all(x[0], y[0], x[1] - x[0], y[1] - y[0], 1);
  891.  
  892.     color(0);
  893.     draw_line(x[0], y[0], ln_oldx, ln_oldy);
  894.     color(OP_COL);
  895.     draw_line(x[0], y[0], x[1], y[1]);
  896.     ln_oldx = x[1];
  897.     ln_oldy = y[1];
  898. }
  899.  
  900. static void
  901. line_term(Object_t * obj)
  902. {
  903.     line_end(obj);
  904.     hide_rect_all();
  905. }
  906.  
  907. static Draw_t *
  908. make_line(void)
  909. {
  910.     static Draw_t dummy;
  911.     Draw_t *d = &dummy;
  912.  
  913.     d->pen_down = line_down;
  914.     d->pen_motion = line_motion;
  915.     d->pen_term = line_term;
  916.     d->redraw = line_redraw;
  917.     d->spray = d->closed = 0;
  918.     d->builtin = 1;
  919.  
  920.     return d;
  921. }
  922.  
  923. /************* END of lines ***************************}**/
  924.  
  925. /***************** Free hand polygons ****************{***/
  926.  
  927.  
  928. static void
  929. fpoly_redraw(Object_t * obj)
  930. {
  931.     long xy[2];
  932.     Pnt_type *x = obj->x, *y = obj->y, *xs = x + obj->n;
  933.  
  934.     for (xs = x + obj->n; x < xs; x++, y++)
  935.       {
  936.       xy[0] = *x;
  937.       xy[1] = *y;
  938.       v2i(xy);
  939.       }
  940. }
  941.  
  942.  
  943. static void
  944. fpoly_motion(Object_t * obj)
  945. {
  946.     int n = obj->n;
  947.     Pnt_type *x = obj->x, *y = obj->y;
  948.     static int oldx, oldy;
  949.  
  950.     if (n == 0)
  951.     return;
  952.  
  953.     color(0);
  954.     draw_line(x[n - 1], y[n - 1], oldx, oldy);
  955.     color(OP_COL);
  956.     draw_line(x[n - 1], y[n - 1], x[n], y[n]);
  957.     oldx = x[n];
  958.     oldy = y[n];
  959. }
  960.  
  961. static void
  962. fpoly_down(Object_t * obj)
  963. {
  964.     int n = obj->n;
  965.  
  966.     if (obj->n == 0)
  967.       {
  968.       obj->n = 1;
  969.       return;
  970.       }
  971. #if 0
  972.     color(OP_COL);
  973.     draw_line(obj->x[n - 1], obj->y[n - 1], obj->x[n], obj->y[n]);
  974. #else
  975.     fpoly_motion(obj);
  976. #endif
  977.     obj->n++;
  978. }
  979.  
  980. static void
  981. fpoly_end(Object_t * obj)
  982. {
  983.     /* remember the last point */
  984.     obj->n++;
  985.     obj->finished = 1;
  986.     paint_it(obj);
  987. }
  988.  
  989. static void
  990. fpoly_term(Object_t * obj)
  991. {
  992.     obj->n = obj->finished = 0;
  993.     clear_over_pup();
  994. }
  995.  
  996. static Draw_t *
  997. make_fpoly(void)
  998. {
  999.     static Draw_t dummy;
  1000.     Draw_t *d = &dummy;
  1001.  
  1002.     d->pen_down = fpoly_down;
  1003.     d->pen_move = null_op;
  1004.     d->pen_motion = fpoly_motion;
  1005.     d->pen_end = fpoly_end;
  1006.     d->pen_term = fpoly_term;
  1007.     d->redraw = fpoly_redraw;
  1008.     d->outline = fpoly_redraw;
  1009.     d->spray = 0;
  1010.     d->closed = 1;
  1011.  
  1012.     return d;
  1013. }
  1014.  
  1015. /************* END of free hand polygons ************}***/
  1016.  
  1017. /********************* Rays *************************{***/
  1018.  
  1019. static int rayshape = 2, raysize;
  1020.  
  1021. /*** Limit end point to some pre-defined shapes **/
  1022. static void
  1023. ray_shape_clip(Object_t * obj)
  1024. {
  1025.     int n = obj->n, r;
  1026.     int xx = obj->x[n] - obj->x[0];
  1027.     int yy = obj->y[n] - obj->y[0];
  1028.     double fact;
  1029.  
  1030.     if (obj->n == 1 && rayshape != 1)
  1031.       {
  1032.       raysize = (rayshape == 2) ? sqrt(xx * xx + yy * yy) :
  1033.           Max(Abs(xx), Abs(yy));
  1034.       return;
  1035.       }
  1036.  
  1037.     switch (rayshape)
  1038.       {
  1039.       case 2:            /* circle */
  1040.       if (((r = xx * xx + yy * yy) > raysize * raysize))
  1041.         {
  1042.         fact = raysize / (0.1 + sqrt(r));
  1043.         obj->x[n] = obj->x[0] + (double) xx *fact;
  1044.         obj->y[n] = obj->y[0] + (double) yy *fact;
  1045.         }
  1046.       break;
  1047.       case 3:            /* square  */
  1048.       if (Abs(xx) > raysize)
  1049.           obj->x[n] = obj->x[0] + (xx > 0 ? 1 : -1) * raysize;
  1050.  
  1051.       if (Abs(yy) > raysize)
  1052.           obj->y[n] = obj->y[0] + (yy > 0 ? 1 : -1) * raysize;
  1053.       break;
  1054.       }
  1055. }
  1056.  
  1057. static void
  1058. ray_redraw(Object_t * obj)
  1059. {
  1060.     int xo = obj->x[0], yo = obj->y[0];
  1061.     Pnt_type *x = obj->x, *y = obj->y, *xs = x + obj->n;
  1062.  
  1063.     while (x < xs)
  1064.     draw_line(xo, yo, *x++, *y++);
  1065.  
  1066. }
  1067.  
  1068. static int rayoldx, rayoldy;
  1069.  
  1070. static void
  1071. ray_down(Object_t * obj)
  1072. {
  1073.     int n = obj->n;
  1074.  
  1075.     if (n == 0)
  1076.       {
  1077.       obj->n = 1;
  1078.       return;
  1079.       }
  1080.  
  1081.     ray_shape_clip(obj);
  1082.  
  1083.     color(OP_COL);
  1084.     draw_line(obj->x[0], obj->y[0], obj->x[n], obj->y[n]);
  1085.     obj->n++;
  1086.  
  1087.     /* invalidate motion record */
  1088.     rayoldx = -1;
  1089. }
  1090.  
  1091. static void
  1092. ray_move(Object_t * obj)
  1093. {
  1094.     /*
  1095.      * we want to have the first two points seperate to define the size of
  1096.      * the circle/sqr
  1097.      */
  1098.     if (obj->n >= 2)
  1099.     ray_down(obj);
  1100. }
  1101.  
  1102. static void
  1103. ray_motion(Object_t * obj)
  1104. {
  1105.     int n = obj->n;
  1106.     Pnt_type *x = obj->x, *y = obj->y;
  1107.  
  1108.     if (!obj->n)
  1109.     return;
  1110.  
  1111.     ray_shape_clip(obj);
  1112.  
  1113.     if (rayoldx > 0)
  1114.       {
  1115.       color(0);
  1116.       draw_line(x[0], y[0], rayoldx, rayoldy);
  1117.       }
  1118.  
  1119.     /* show size and theta, among other things */
  1120.     show_rect_all(x[0], y[0], x[n] - x[0], y[n] - y[0], 1);
  1121.  
  1122.     color(OP_COL);
  1123.     draw_line(x[0], y[0], x[n], y[n]);
  1124.  
  1125.     /*
  1126.      * this is necessary because near center region is wiped out by the
  1127.      * moving ray. Adding this looks MUCH better
  1128.      */
  1129.     ray_redraw(obj);
  1130.  
  1131.     rayoldx = x[n];
  1132.     rayoldy = y[n];
  1133. }
  1134.  
  1135. static void
  1136. ray_end(Object_t * obj)
  1137. {
  1138.     obj->finished = 1;
  1139.     paint_it(obj);
  1140. }
  1141.  
  1142. static void
  1143. ray_option(void)
  1144. {
  1145.     static char *rayopt = "RayOption%t|Free|Circle|Square";
  1146.     static long raymenu = -1;
  1147.     int tray;
  1148.  
  1149.     /* block while current object has not finished */
  1150.     if (cur_obj.n > 1)
  1151.     return;
  1152.  
  1153.     if (raymenu < 0)
  1154.     raymenu = defpup(rayopt);
  1155.  
  1156.     if ((tray = dopup(raymenu)) > 0)
  1157.     rayshape = tray;
  1158. }
  1159.  
  1160. static Draw_t *
  1161. make_ray(void)
  1162. {
  1163.     static Draw_t dummy;
  1164.     Draw_t *d = &dummy;
  1165.  
  1166.     d->redraw = ray_redraw;
  1167.     d->pen_down = ray_down;
  1168.     d->pen_move = ray_move;
  1169.     d->pen_end = ray_end;
  1170.     d->pen_motion = ray_motion;
  1171.     d->option = ray_option;
  1172.     d->closed = 0;
  1173.     d->builtin = 1;
  1174.  
  1175.     return d;
  1176. }
  1177.  
  1178. /************** END of Rays ***********************}***/
  1179.  
  1180. /********************* Erasor *********************{**/
  1181.  
  1182. static int ex = 20, ey = 20;
  1183.  
  1184. static void
  1185. erasor_term(Object_t * obj)
  1186. {
  1187.     rubber_finish();
  1188.     obj->n = obj->finished = 0;
  1189. }
  1190.  
  1191. static void
  1192. erasor_move(Object_t * obj)
  1193. {
  1194.     int n = obj->n;
  1195.     int xi = obj->x[n] - ex / 2, yi = obj->y[n] - ey / 2;
  1196.  
  1197.     drawmode(NORMALDRAW);
  1198.     reshapeviewport();
  1199.     rubber_moveto(&xi, &yi, &ex, &ey);
  1200.  
  1201.     /* redraw the area covered by rubber band */
  1202.     dbl_rect_redraw(saved, xi, yi, ex, ey);
  1203.  
  1204.     /* change the image in core */
  1205.     fb_to_ras(imgptr, make_rect(xi, yi, ex, ey));
  1206. }
  1207.  
  1208. static void
  1209. erasor_motion(Object_t * obj)
  1210. {
  1211.     int n = obj->n;
  1212.     int xi = obj->x[n] - ex / 2, yi = obj->y[n] - ey / 2;
  1213.     short val;
  1214.  
  1215.     linewidth(1);
  1216.  
  1217.     set_rubber_bounds(1, imgptr->xi, imgptr->yi, imgptr->w, imgptr->h);
  1218.  
  1219.     if (n == 0)
  1220.       {
  1221.       set_rubber_obj(RB_RECT);
  1222.       (void) rubber_cursor(win_id, &val, &xi, &yi, ex, ey, 2);
  1223.       obj->n = 1;
  1224.       }
  1225.     rubber_moveto(&xi, &yi, &ex, &ey);
  1226. }
  1227.  
  1228. static void
  1229. erasor_option(void)
  1230. {
  1231.     static long emenu = -1;
  1232.     int n;
  1233.  
  1234.     if (emenu < 0)
  1235.     emenu = defpup("Erasor%t|10x10|20x20|30x30|40x40|50x50");
  1236.  
  1237.     if ((n = dopup(emenu)) > 0)
  1238.     ex = ey = 10 * n;
  1239. }
  1240.  
  1241. static Draw_t *
  1242. make_erasor(void)
  1243. {
  1244.     static Draw_t dummy;
  1245.     Draw_t *d = &dummy;
  1246.  
  1247.     d->pen_down = erasor_move;
  1248.     d->redraw = null_op;
  1249.     d->pen_move = erasor_move;
  1250.     d->pen_motion = erasor_motion;
  1251.     d->pen_term = erasor_term;
  1252.     d->option = erasor_option;
  1253.     d->closed = 0;
  1254.     d->builtin = 1;
  1255.  
  1256.     return d;
  1257. }
  1258.  
  1259. /************ END of erasor **********************************}***/
  1260.  
  1261. /******************* Air Brush **************{**/
  1262.  
  1263. #define MAX_AB_SIZE 35        /* max brush size */
  1264.  
  1265. static int abx = 20;        /* air brush size */
  1266. static int aby = 20;        /* air brush size */
  1267.  
  1268. static FL_FORM *create_form_fspray(void);
  1269. static void spray_option(void);
  1270.  
  1271. #ifdef __STRICT_ANSI__
  1272. extern long random(void);
  1273. #endif
  1274.  
  1275. /* flow rate is something artificial, 1.0 being max */
  1276. static float arate = 0.5;    /* flow rate      */
  1277.  
  1278. /***** Generate "good" points **/
  1279. static void
  1280. get_circ_points(int n, Pnt_type * x, Pnt_type * y, int range)
  1281. {
  1282.     int rsq = range * range;
  1283.     int i;
  1284.  
  1285.     for (i = 0; i < n;)
  1286.       {
  1287.       *x = range * (float) ((random() % 10001) / 10000.0 * 2.0 - 1.0);
  1288.       *y = range * (float) ((random() % 10001) / 10000.0 * 2.0 - 1.0);
  1289.  
  1290.       if ((*x) * (*x) + (*y) * (*y) < rsq)
  1291.         {
  1292.         i++;
  1293.         x++;
  1294.         y++;
  1295.         }
  1296.       }
  1297. }
  1298.  
  1299. static void
  1300. get_rect_points(int n, Pnt_type * x, Pnt_type * y, int range)
  1301. {
  1302.     int i;
  1303.  
  1304.     for (i = 0; i < n;)
  1305.       {
  1306.       *x = range * (float) ((random() % 10001) / 10000.0 * 2.0 - 1.0);
  1307.       *y = range * (float) ((random() % 10001) / 10000.0 * 2.0 - 1.0);
  1308.  
  1309.       if (*x < range && *y < range)
  1310.         {
  1311.         i++;
  1312.         x++;
  1313.         y++;
  1314.         }
  1315.       }
  1316. }
  1317.  
  1318. static int
  1319. points_to_spray(int N)
  1320. {
  1321.     int m;
  1322.     return ((m = 0.25 * arate * abx * aby) > N / 2) ? N / 2 : ((m < 8) ? 8 : m);
  1323. }
  1324.  
  1325. /*
  1326.  * instead of letting paint driver do the rasterization, we can
  1327.  * manipulate the virtual framebuffer directly
  1328.  */
  1329. static void
  1330. spray_and_rasterize(Pnt_type * xx, Pnt_type * yy, int m, int x, int y)
  1331. {
  1332.     register rgba_t cc = Pack(ccol[0], ccol[1], ccol[2]);
  1333.     register int xi = imgptr->xi, yi = imgptr->yi;
  1334.     register int w = imgptr->w, h = imgptr->h;
  1335.     register int i, px, py;
  1336.     register rgba_t **vfb = imgptr->mraster;
  1337.     long xy[2];
  1338.  
  1339.     bgnpoint();
  1340.     for (i = 0; i < m; i++)
  1341.       {
  1342.       xy[0] = x + xx[i];
  1343.       xy[1] = y + yy[i];
  1344.       v2i(xy);
  1345.  
  1346.       /* px, py are relative to image */
  1347.       px = xy[0] - xi;
  1348.       py = xy[1] - yi;
  1349.       if (px >= 0 && py >= 0 && px < w && py < h)
  1350.           vfb[py][px] = cc;
  1351.       }
  1352.     endpoint();
  1353. }
  1354.  
  1355.  
  1356. static void
  1357. circ_airbrush(Object_t * obj)
  1358. {
  1359.     int n = obj->n, m;
  1360.     Pnt_type xx[512], yy[512];
  1361.     int x = obj->x[n], y = obj->y[n];
  1362.  
  1363.     m = points_to_spray(512);
  1364.     get_circ_points(m, xx, yy, abx);
  1365.     spray_and_rasterize(xx, yy, m, x, y);
  1366. }
  1367.  
  1368. static void
  1369. rect_airbrush(Object_t * obj)
  1370. {
  1371.     int n = obj->n, m;
  1372.     int x = obj->x[n], y = obj->y[n];
  1373.     Pnt_type xx[512], yy[512];
  1374.  
  1375.     m = points_to_spray(512);
  1376.     get_rect_points(m, xx, yy, abx);
  1377.     spray_and_rasterize(xx, yy, m, x, y);
  1378.  
  1379. }
  1380.  
  1381. /** Looks nicer to use more HVHASH **/
  1382. static int beffects[] =
  1383. {
  1384.     PAT_RHASH, PAT_GRID_DOTS, PAT_LHASH, PAT_HVHASH, PAT_HHASH,
  1385.     PAT_GRID_DOTS, PAT_HVHASH,
  1386. };
  1387.  
  1388. static int cur_effects, neffects = sizeof(beffects) / sizeof(beffects[0]);
  1389.  
  1390. static void
  1391. net_airbrush(Object_t * obj)
  1392. {
  1393.     int n = obj->n;
  1394.     int x_n = obj->x[n], y_n = obj->y[n];
  1395.     static int lx, ly;
  1396.  
  1397.     /* add a threshold make it better on fast machines */
  1398.     if (Abs(x_n - lx) > abx / 3 || Abs(y_n - ly) > aby / 3)
  1399.       {
  1400.       setpattern(beffects[cur_effects++]);
  1401.       gl_circ(x_n, y_n, 2 * abx - 1, 2 * aby - 1, 1, 0);
  1402.       cur_effects %= neffects;
  1403.       lx = x_n;
  1404.       ly = y_n;
  1405.       setpattern(0);
  1406.       }
  1407. }
  1408.  
  1409.  
  1410. typedef struct
  1411. {
  1412.     char *bitmap;        /* nozzle shape bitmap */
  1413.     int cur_min;        /* min. size cursor    */
  1414.     int cur_max;        /* max. size cursor    */
  1415.     void (*spray) (Object_t *);    /* how */
  1416. }
  1417. AirBrush;
  1418.  
  1419. static AirBrush abrushes[] =
  1420. {
  1421.     {circ_bits, CUR_CIRC10, CUR_CIRC30, circ_airbrush},
  1422.     {rec_bits, CUR_RECT10, CUR_RECT30, rect_airbrush},
  1423.     {ray_bits, CUR_CIRCNET, CUR_CIRCNET, net_airbrush}
  1424. };
  1425.  
  1426. static int cur_abrush;
  1427.  
  1428. static void (*spray_it) (Object_t *);
  1429.  
  1430. /* ARGSUSED */
  1431. static void
  1432. spray_init(Object_t * obj)
  1433. {
  1434.     AirBrush *ab = abrushes + cur_abrush;
  1435.     int cursor;
  1436.  
  1437.     reset_time();
  1438.     cursor = ab->cur_min + (abx / 10);
  1439.     if (cursor > ab->cur_max)
  1440.     cursor = ab->cur_max;
  1441.     set_cursor(win_id, cursor);
  1442.     set_default_cursor(win_id, cursor);
  1443.     spray_it = ab->spray;
  1444. }
  1445.  
  1446. /**************************************************************/
  1447. static void
  1448. spray_move(Object_t * obj)
  1449. {
  1450.     static int lx, ly;
  1451.     int n = obj->n;
  1452. #if 1
  1453.     int t = (1.0 / (arate + 0.01));
  1454.  
  1455.     t = (t > 20) ? 20 : t;
  1456.  
  1457.     if ((lx == obj->x[n]) && (ly == obj->y[n]) && time_passed() < t)
  1458.     return;
  1459.  
  1460.     reset_time();
  1461. #endif
  1462.     set_current_window(win_id);
  1463.     drawmode(NORMALDRAW);
  1464.     reshapeviewport();
  1465.     frontbuffer(1);
  1466.     backbuffer(1);
  1467.     Color4(ccol);
  1468.  
  1469.     spray_it(obj);
  1470.  
  1471.     if ((lx - obj->x[n]) || (ly - obj->y[n]))
  1472.       {
  1473.       lx = obj->x[n];
  1474.       ly = obj->y[n];
  1475.       obj->n++;
  1476.       }
  1477.  
  1478.     frontbuffer(!double_buf);
  1479. }
  1480.  
  1481. static void
  1482. spray_up(Object_t * obj)
  1483. {
  1484.     int oldlw = cur_lw;
  1485.  
  1486.     /* only net_spray need to be rasterized by the paint driver */
  1487.     if (spray_it == net_airbrush)
  1488.       {
  1489.       obj->n++;
  1490.       obj->finished = 1;
  1491.  
  1492.       /* accumalation routine take lw/2 */
  1493.       /* cur_lw = MAX_AB_SIZE; */
  1494.       cur_lw = Max(abx, aby);
  1495.       paint_it(obj);
  1496.       cur_lw = oldlw;
  1497.       }
  1498.     obj->n = obj->finished = 0;
  1499. }
  1500.  
  1501. /* ARGSUSED */
  1502. static void
  1503. spray_term(Object_t * obj)
  1504. {
  1505.     set_default_cursor(win_id, CUR_DEFAULT);
  1506.     reset_cursor(win_id);
  1507.  
  1508. }
  1509.  
  1510. static Draw_t *
  1511. make_spray(void)
  1512. {
  1513.     static Draw_t dummy;
  1514.     Draw_t *d = &dummy;
  1515.  
  1516.     d->pen_init = spray_init;
  1517.     d->pen_down = spray_move;
  1518.     d->pen_move = spray_move;
  1519.     d->pen_up = spray_up;
  1520.     d->redraw = null_op;
  1521.     d->pen_term = spray_term;
  1522.     d->option = spray_option;
  1523.     d->spray = 1;
  1524.     d->builtin = 1;
  1525.     return d;
  1526. }
  1527.  
  1528. /*** get spray options ****/
  1529. static void
  1530. spray_option(void)
  1531. {
  1532.     short val;
  1533.  
  1534.     bit_show_form(create_form_fspray(), FL_PLACE_MOUSE, 0, "SprayOption");
  1535.  
  1536.     while (bit_qread(&val) != F1KEY || !val)
  1537.     ;
  1538.     bit_hide_form(create_form_fspray());
  1539. }
  1540.  
  1541. /* ARGSUSED */
  1542. static void
  1543. spray_tools(FL_OBJECT * ob, long q)
  1544. {
  1545.     flush_object(&cur_obj);
  1546.     cur_abrush = q;
  1547.     spray_init(&cur_obj);
  1548. }
  1549.  
  1550. /*ARGSUSED */
  1551. static void
  1552. spray_size_cb(FL_OBJECT * ob, long q)
  1553. {
  1554.     flush_object(&cur_obj);
  1555.     abx = aby = fl_get_counter_value(ob);
  1556.     spray_init(&cur_obj);
  1557. }
  1558.  
  1559. /*ARGSUSED */
  1560. static void
  1561. spray_rate_cb(FL_OBJECT * ob, long q)
  1562. {
  1563.     arate = fl_get_slider_value(ob);
  1564. }
  1565.  
  1566. /*ARGSUSED */
  1567. static void
  1568. spray_opt_end(FL_OBJECT * ob, long q)
  1569. {
  1570.     fl_qenter(F1KEY, 1);
  1571. }
  1572.  
  1573. static FL_FORM *
  1574. create_form_fspray(void)
  1575. {
  1576.     static FL_FORM *fspray;
  1577.     FL_OBJECT *obj;
  1578.     float x, y, dx, dy;
  1579.     int i;
  1580.  
  1581.     if (fspray)
  1582.     return fspray;
  1583.  
  1584.     fspray = fl_bgn_form(FL_NO_BOX, 190.0, 215.0);
  1585.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 190.0, 215.0, "");
  1586.     fl_set_object_color(obj, 12, 47);
  1587.  
  1588.     obj = fl_add_box(FL_DOWN_BOX, 10.0, 45.0, 170.0, 160.0, "");
  1589.     fl_set_object_color(obj, 9, 47);
  1590.  
  1591.     fl_bgn_group();
  1592.  
  1593.     x = 30;
  1594.     y = 155;
  1595.     dx = 40;
  1596.     dy = 40;
  1597.     for (i = 0; i < 3; i++, x += dx + 5)
  1598.       {
  1599.  
  1600.       obj = fl_add_active_bitmap(FL_RADIO_BITMAP, x, y, dx, dy, "");
  1601.       fl_set_bitmap_bitmap(obj, BITMAP_W, BITMAP_H, abrushes[i].bitmap);
  1602.       fl_set_call_back(obj, spray_tools, i);
  1603.       if (i == cur_abrush)
  1604.           fl_set_active_bitmap(obj, 1);
  1605.       }
  1606.  
  1607.     fl_end_group();
  1608.  
  1609.     obj = fl_add_valslider(FL_HNS, 20.0, 55.0, 150.0, 25.0, "FlowRate");
  1610.     fl_set_object_color(obj, 9, 47);
  1611.     fl_set_object_lsize(obj, 10.000000);
  1612.     fl_set_object_align(obj, FL_ALIGN_TOP);
  1613.     fl_set_slider_bounds(obj, 0.01, 1.0);
  1614.     fl_set_slider_value(obj, 0.5);
  1615.     fl_set_call_back(obj, spray_rate_cb, 0);
  1616.  
  1617.     obj = fl_add_counter(FL_NC, 30.0, 105.0, 130.0, 25.0, "NozzleSize");
  1618.     fl_set_object_lsize(obj, 10.000000);
  1619.     fl_set_object_align(obj, FL_ALIGN_TOP);
  1620.     fl_set_counter_step(obj, 1, 5);
  1621.     fl_set_counter_bounds(obj, 5, 32);
  1622.     fl_set_counter_value(obj, 10);
  1623.     fl_set_call_back(obj, spray_size_cb, 0);
  1624.  
  1625.     obj = fl_add_button(FL_NORMAL_BUTTON, 125.0, 10.0, 55.0, 25.0, "OK");
  1626.     fl_set_object_lsize(obj, 10.000000);
  1627.     fl_set_call_back(obj, spray_opt_end, 0);
  1628.     fl_end_form();
  1629.     return fspray;
  1630. }
  1631.  
  1632. /***** END of Spray function ******************* }**/
  1633.  
  1634. static int
  1635. if_center(void)
  1636. {
  1637.     static long centered = -1;
  1638.     if (centered < 0)
  1639.     centered = defpup("CenterOpt%t|default|center");
  1640.     return dopup(centered) - 1;
  1641. }
  1642.  
  1643. /************** Circles **************************************{**/
  1644.  
  1645. static int circ_centered;
  1646. static int circ_x, circ_y, circ_dx, circ_dy;
  1647.  
  1648. static void
  1649. circ_position(int xi, int yi, int xf, int yf)
  1650. {
  1651.     if (circ_centered)
  1652.       {
  1653.       circ_x = xi;
  1654.       circ_y = yi;
  1655.       circ_dx = 2 * (xf - xi);
  1656.       circ_dy = 2 * (yf - yi);
  1657.       }
  1658.     else
  1659.       {
  1660.       circ_x = (xi + xf) / 2;
  1661.       circ_y = (yi + yf) / 2;
  1662.       circ_dx = xf - xi + 1;
  1663.       circ_dy = yf - yi + 1;
  1664.       }
  1665.  
  1666.     /* again, need to canonicalize the size */
  1667.     if (circ_dx < 0)
  1668.     circ_dx = -circ_dx;
  1669.  
  1670.     if (circ_dy < 0)
  1671.     circ_dy = -circ_dy;
  1672. }
  1673.  
  1674. static void
  1675. circ_redraw(Object_t * obj)
  1676. {
  1677.     circ_position(obj->x[0], obj->y[0], obj->x[1], obj->y[1]);
  1678.     gl_circ(circ_x, circ_y, circ_dx, circ_dy, cur_pat != PAT_HOLLOW, 0);
  1679. }
  1680.  
  1681. static void
  1682. circ_outline(Object_t * obj)
  1683. {
  1684.     int opat = cur_pat;
  1685.  
  1686.     cur_pat = PAT_HOLLOW;
  1687.     circ_redraw(obj);
  1688.     cur_pat = opat;
  1689. }
  1690.  
  1691. static void
  1692. circ_move(Object_t * obj)
  1693. {
  1694.     static int oldx, oldy;
  1695.     Pnt_type *x = obj->x, *y = obj->y;
  1696.  
  1697.     if (obj->n == 0)
  1698.       {
  1699.       oldx = x[0];
  1700.       oldy = y[0];
  1701.       obj->n = 1;
  1702.       return;
  1703.       }
  1704.  
  1705.     circ_position(x[0], y[0], oldx, oldy);
  1706.     color(0);
  1707.     gl_circ(circ_x, circ_y, circ_dx, circ_dy, 0, 0);
  1708.  
  1709.     circ_position(x[0], y[0], x[1], y[1]);
  1710.     color(OP_COL);
  1711.     gl_circ(circ_x, circ_y, circ_dx, circ_dy, 0, 0);
  1712.  
  1713.     oldx = x[1];
  1714.     oldy = y[1];
  1715. }
  1716.  
  1717. static void
  1718. circ_up(Object_t * obj)
  1719. {
  1720.     obj->n = 2;
  1721.     obj->finished = 1;
  1722.  
  1723.     /*
  1724.      * due to two different type of circles, need to handle segment manually
  1725.      * here. Also due to anti-aliasing, give a couple of more pixels to save
  1726.      */
  1727.     circ_position(obj->x[0], obj->y[0], obj->x[1], obj->y[1]);
  1728.     add_segment(circ_x - circ_dx / 2 - 1, circ_y - circ_dy / 2 - 1,
  1729.         circ_dx + 2, circ_dy + 2);
  1730.     paint_it(obj);
  1731. }
  1732.  
  1733. static void
  1734. circ_option(void)
  1735. {
  1736.     circ_centered = if_center() == 1;
  1737. }
  1738.  
  1739. static Draw_t *
  1740. make_circ(void)
  1741. {
  1742.     static Draw_t dummy;
  1743.     Draw_t *d = &dummy;
  1744.  
  1745.     d->pen_down = circ_move;
  1746.     d->pen_move = circ_move;
  1747.     d->redraw = circ_redraw;
  1748.     d->pen_up = circ_up;
  1749.     d->option = circ_option;
  1750.     d->outline = circ_outline;
  1751.     d->closed = 1;
  1752.     d->builtin = 1;
  1753.  
  1754.     return d;
  1755. }
  1756.  
  1757. /***** END of circles **********************}*****/
  1758.  
  1759. /************** Rectangles ********************************{****/
  1760.  
  1761. static int sqr_centered;
  1762. static int sqr_x, sqr_y, sqr_dx, sqr_dy;
  1763.  
  1764. static void
  1765. sqr_position(int xi, int yi, int xf, int yf)
  1766. {
  1767.     if (sqr_centered)
  1768.       {
  1769.       sqr_x = xi;
  1770.       sqr_y = yi;
  1771.       sqr_dx = 2 * (xf - xi);
  1772.       sqr_dy = 2 * (yf - yi);
  1773.       }
  1774.     else
  1775.       {
  1776.       sqr_x = (xi + xf) / 2;
  1777.       sqr_y = (yi + yf) / 2;
  1778.       sqr_dx = (xf - xi);
  1779.       sqr_dy = (yf - yi);
  1780.       }
  1781.  
  1782.     if (sqr_dx < 0)
  1783.     sqr_dx = -sqr_dx;
  1784.  
  1785.     if (sqr_dy < 0)
  1786.     sqr_dy = -sqr_dy;
  1787. }
  1788.  
  1789. static void
  1790. sqr_redraw(Object_t * obj)
  1791. {
  1792.     sqr_position(obj->x[0], obj->y[0], obj->x[1], obj->y[1]);
  1793.     gl_rect(sqr_x, sqr_y, sqr_dx, sqr_dy, cur_pat != PAT_HOLLOW, 0);
  1794. }
  1795.  
  1796. static void
  1797. sqr_outline(Object_t * obj)
  1798. {
  1799.     int opat = cur_pat;
  1800.  
  1801.     cur_pat = PAT_HOLLOW;
  1802.     sqr_redraw(obj);
  1803.     cur_pat = opat;
  1804. }
  1805.  
  1806. static void
  1807. sqr_move(Object_t * obj)
  1808. {
  1809.     static int oldx, oldy;
  1810.  
  1811.     if (obj->n == 0)
  1812.       {
  1813.       oldx = obj->x[0];
  1814.       oldy = obj->y[0];
  1815.       obj->n = 1;
  1816.       return;
  1817.       }
  1818.  
  1819.     color(0);
  1820.     sqr_position(obj->x[0], obj->y[0], oldx, oldy);
  1821.     gl_rect(sqr_x, sqr_y, sqr_dx, sqr_dy, 0, 0);
  1822.  
  1823.     color(OP_COL);
  1824.     sqr_position(obj->x[0], obj->y[0], obj->x[1], obj->y[1]);
  1825.     gl_rect(sqr_x, sqr_y, sqr_dx, sqr_dy, 0, 0);
  1826.  
  1827.     oldx = obj->x[1];
  1828.     oldy = obj->y[1];
  1829. }
  1830.  
  1831. static void
  1832. sqr_up(Object_t * obj)
  1833. {
  1834.     obj->n = 2;
  1835.     obj->finished = 1;
  1836.  
  1837.     /*
  1838.      * due to two different type of rectangles, need to handle segment
  1839.      * manually here
  1840.      */
  1841.     sqr_position(obj->x[0], obj->y[0], obj->x[1], obj->y[1]);
  1842.     add_segment(sqr_x - sqr_dx / 2 - 1, sqr_y - sqr_dy / 2 - 1,
  1843.         sqr_dx + 2, sqr_dy + 2);
  1844.     paint_it(obj);
  1845. }
  1846.  
  1847. static void
  1848. sqr_option(void)
  1849. {
  1850.     sqr_centered = if_center() == 1;
  1851. }
  1852.  
  1853. static Draw_t *
  1854. make_sqr(void)
  1855. {
  1856.     static Draw_t dummy;
  1857.     Draw_t *d = &dummy;
  1858.  
  1859.     d->pen_down = sqr_move;
  1860.     d->pen_move = sqr_move;
  1861.     d->redraw = sqr_redraw;
  1862.     d->pen_up = sqr_up;
  1863.     d->option = sqr_option;
  1864.     d->outline = sqr_outline;
  1865.     d->closed = 1;
  1866.     d->builtin = 1;
  1867.  
  1868.     return d;
  1869. }
  1870.  
  1871. /************* END of rectanges ****************}***/
  1872.  
  1873. /**** Pencils ***********************{***/
  1874.  
  1875. static void
  1876. pencil_redraw(Object_t * obj)
  1877. {
  1878.     float xy[2];
  1879.     Pnt_type *x = obj->x, *y = obj->y, *xs = x + obj->n;
  1880.  
  1881.     if (cur_lw <= 0)
  1882.     return;
  1883.  
  1884.     while (x < xs)
  1885.       {
  1886.       xy[0] = *x++;
  1887.       xy[1] = *y++;
  1888.       v2f(xy);
  1889.       }
  1890. }
  1891.  
  1892. static void
  1893. pencil_move(Object_t * obj)
  1894. {
  1895.     int n = obj->n;
  1896.  
  1897.     if (obj->n == 0)
  1898.       {
  1899.       obj->n = 1;
  1900.       return;
  1901.       }
  1902.  
  1903.     color(OP_COL);
  1904.     draw_line(obj->x[n - 1], obj->y[n - 1], obj->x[n], obj->y[n]);
  1905.  
  1906.     /* can't have more than 256 vertex */
  1907.     if (obj->n > 250)
  1908.     flush_object(obj);
  1909.     else
  1910.     obj->n++;
  1911. }
  1912.  
  1913. static void
  1914. pencil_up(Object_t * obj)
  1915. {
  1916.     obj->finished = 1;
  1917.     paint_it(obj);
  1918. }
  1919.  
  1920. static Draw_t *
  1921. make_pencil(void)
  1922. {
  1923.     static Draw_t dummy;
  1924.     Draw_t *d = &dummy;
  1925.  
  1926.     d->pen_down = pencil_move;
  1927.     d->pen_up = pencil_up;
  1928.     d->pen_move = pencil_move;
  1929.     d->redraw = pencil_redraw;
  1930.     d->closed = 0;
  1931.  
  1932.     return d;
  1933. }
  1934.  
  1935. /************ END of pencils ************************}****/
  1936.  
  1937. /************* CUT & PASTE ***************************{*/
  1938.  
  1939. static void **cutbuf;        /* raster being cut     */
  1940. static Rect_t cutsize;        /* cut size             */
  1941. static int cp_oldx, cp_oldy;    /* position of pen_down */
  1942.  
  1943. /*************************************************************
  1944.  * check if current mouse click is within the rectangle formed
  1945.  * by point 0 and point 1
  1946.  *************************************************************/
  1947.  
  1948. static int
  1949. inbounds(Object_t * obj)
  1950. {
  1951.     const Rect_t *r;
  1952.     Pnt_type *x = obj->x, *y = obj->y;
  1953.  
  1954.     if (obj->n < 2)
  1955.     return 0;
  1956.  
  1957.     r = make_rect(x[0], y[0], x[1] - x[0] + 1, y[1] - y[0] + 1);
  1958.     return inside_rect(x[2], y[2], r);
  1959. }
  1960.  
  1961. static void
  1962. cut_it(Object_t * obj)
  1963. {
  1964.     Rect_t rdummy;
  1965.     Rect_t *r = &rdummy;
  1966.     Pnt_type *x = obj->x, *y = obj->y;
  1967.  
  1968.     if (cutbuf)
  1969.     return;
  1970.  
  1971.     copy_rect(r, make_rect(x[0], y[0], x[1] - x[0] + 1, y[1] - y[0] + 1));
  1972.     canonicalize_rect(r);
  1973.  
  1974.     /* canonicalize the obeject as well */
  1975.     x[0] = r->x;
  1976.     y[0] = r->y;
  1977.     x[1] = r->x + r->w - 1;
  1978.     y[1] = r->y + r->h - 1;
  1979.  
  1980.     cutbuf = no_fail_get_subimage(imgptr, r->x, r->y, r->w, r->h);
  1981.     cutsize = *r;
  1982. }
  1983.  
  1984. static void
  1985. cp_down(Object_t * obj)
  1986. {
  1987.     if (obj->n < 2)
  1988.     return;
  1989.  
  1990.     clear_over_pup();
  1991.  
  1992.     if (!inbounds(obj))
  1993.       {
  1994.       set_current_window(win_id);
  1995.       switch_frame_buffer();
  1996.       obj->n = 0;
  1997.       obj->x[0] = obj->x[2];
  1998.       obj->y[0] = obj->y[2];
  1999.       }
  2000.     else
  2001.       {
  2002.       cut_it(obj);
  2003.       }
  2004.  
  2005.     cp_oldx = obj->x[2];
  2006.     cp_oldy = obj->y[2];
  2007. }
  2008.  
  2009. static void
  2010. cp_move(Object_t * obj)
  2011. {
  2012.     int dx, dy;
  2013.     Rect_t *cs = &cutsize;
  2014.  
  2015.     if (obj->n < 2)
  2016.       {
  2017.       sqr_move(obj);
  2018.       if (cutbuf)
  2019.         {
  2020.         free_mat(cutbuf);
  2021.         cutbuf = 0;
  2022.         drawmode(NORMALDRAW);
  2023.         dbl_rect_redraw(imgptr, cs->x, cs->y, cs->w, cs->h);
  2024.         switch_frame_buffer();
  2025.         }
  2026.       return;
  2027.       }
  2028.  
  2029.     set_current_window(win_id);
  2030.     drawmode(NORMALDRAW);
  2031.     reshapeviewport();
  2032.  
  2033.  
  2034.     dx = obj->x[2] - cp_oldx;
  2035.     dy = obj->y[2] - cp_oldy;
  2036.  
  2037.  
  2038.     shift_object(obj, dx, dy);
  2039.  
  2040.     mv_ras_obj(cutbuf, cs->w, cs->h, cs->x, cs->y, cs->x + dx, cs->y + dy);
  2041.  
  2042.     shift_rect(cs, dx, dy);
  2043.  
  2044.     cp_oldx = obj->x[2];
  2045.     cp_oldy = obj->y[2];
  2046.  
  2047.  
  2048.     switch_frame_buffer();
  2049. }
  2050.  
  2051. static void
  2052. cp_up(Object_t * obj)
  2053. {
  2054.     set_current_window(win_id);
  2055.     switch_frame_buffer();
  2056.     obj->n = 1;
  2057.     color(OP_COL);
  2058.     sqr_move(obj);
  2059.     obj->n = 2;
  2060.     drawmode(NORMALDRAW);
  2061. }
  2062.  
  2063. static void
  2064. cp_redraw(Object_t * obj)
  2065. {
  2066.     Rect_t *cs = &cutsize;
  2067.  
  2068.     /*
  2069.      * after a window manager redraw event, the rectangle and cut buffer
  2070.      * might be at different locations
  2071.      */
  2072.  
  2073.     if (obj->n >= 2 && (cs->x != obj->x[0] || cs->y != obj->y[0]))
  2074.       {
  2075.       cs->x = obj->x[0];
  2076.       cs->y = obj->y[0];
  2077.       }
  2078.  
  2079. }
  2080.  
  2081. /* ARGSUSED */
  2082. static void
  2083. cp_end(Object_t * obj)
  2084. {
  2085.     Rect_t *cs = &cutsize;
  2086.     /*
  2087.      * here we operate on the image directly to avoid reading a (possibly)
  2088.      * dithered framebuffer
  2089.      */
  2090.  
  2091.     if (cutbuf)
  2092.       {
  2093.       put_subimage(imgptr, cutbuf, cs, 0);
  2094.       dbl_rect_redraw(imgptr, cs->x, cs->y,
  2095.               cs->x + cs->w - 1, cs->y + cs->h - 1);
  2096.       }
  2097. }
  2098.  
  2099. static void
  2100. cp_term(Object_t * obj)
  2101. {
  2102.     obj->n = obj->finished = 0;
  2103.     cp_move(obj);
  2104.     obj->n = 0;
  2105.     clear_over_pup();
  2106.     drawmode(NORMALDRAW);
  2107.     reshapeviewport();
  2108. }
  2109.  
  2110. static void
  2111. cp_motion(Object_t * obj)
  2112. {
  2113.  
  2114.     if (obj->n == 0)
  2115.     return;
  2116.  
  2117.     set_cursor(win_id, inbounds(obj) ? CUR_HAND : CUR_DEFAULT);
  2118. }
  2119.  
  2120. static Draw_t *
  2121. make_cut_paste(void)
  2122. {
  2123.     static Draw_t dummy;
  2124.     Draw_t *d = &dummy;
  2125.  
  2126.     d->pen_down = cp_down;
  2127.     d->pen_move = cp_move;
  2128.     d->pen_up = cp_up;
  2129.     d->pen_end = cp_end;
  2130.     d->pen_term = cp_term;
  2131.     d->pen_motion = cp_motion;
  2132.     d->redraw = cp_redraw;
  2133.  
  2134.     return d;
  2135. }
  2136.  
  2137. /**** END OF cut&paste ****************/
  2138.  
  2139. /*****************************************************************
  2140.  *   Brush
  2141.  *   Based on "stroke" model: any pen moved is acomplished by
  2142.  *   stroking from (xi,yi) to (xf, yf)
  2143.  **************************************************************{**/
  2144.  
  2145. #define BS_BW   20        /* brush bitmap width */
  2146. #define BS_BH   20        /* brush bitmap height */
  2147.  
  2148. #include "bitmaps/bs_circ.xbm"
  2149. #include "bitmaps/bs_rline.xbm"
  2150. #include "bitmaps/bs_lline.xbm"
  2151. #include "bitmaps/bs_rect.xbm"
  2152. #include "bitmaps/bs_hline.xbm"
  2153. #include "bitmaps/bs_vline.xbm"
  2154.  
  2155. typedef struct
  2156. {
  2157.     int cursor_name;        /* cursor names        */
  2158.     char *bits;            /* brush shape bitmaps */
  2159.     void (*stroke) (int, int, int, int);
  2160. }
  2161. Brush_t;
  2162.  
  2163. static int get_brush_shape(void);
  2164. static void rline_stroke(int, int, int, int);
  2165. static void lline_stroke(int, int, int, int);
  2166. static void hline_stroke(int, int, int, int);
  2167. static void vline_stroke(int, int, int, int);
  2168. static void circ_stroke(int, int, int, int);
  2169. static void rect_stroke(int, int, int, int);
  2170.  
  2171. static Brush_t brushes[] =
  2172. {
  2173.     {CUR_L_LINE, bslline_bits, lline_stroke},
  2174.     {CUR_R_LINE, bsrline_bits, rline_stroke},
  2175.     {CUR_H_LINE, bshline_bits, hline_stroke},
  2176.     {CUR_V_LINE, bsvline_bits, vline_stroke},
  2177.     {CUR_S_DISK, bscirc_bits, circ_stroke},
  2178.     {CUR_S_FRECT, bsrect_bits, rect_stroke},
  2179. };
  2180.  
  2181. static int nbrushes = sizeof(brushes) / sizeof(brushes[0]);
  2182. static Brush_t *cur_brush = &brushes[0];
  2183. static void (*cur_stroke) (int, int, int, int);
  2184.  
  2185. static int bx = 10, by = 10;    /* brush size. better to even */
  2186.  
  2187. static void
  2188. hline_stroke(int xi, int yi, int xf, int yf)
  2189. {
  2190.     float xy[2];
  2191.  
  2192.     bgnpolygon();
  2193.     {
  2194.     xy[0] = xi - bx / 2;
  2195.     xy[1] = yi;
  2196.     v2f(xy);
  2197.  
  2198.     xy[0] = xi + bx / 2;
  2199.     xy[1] = yi;
  2200.     v2f(xy);
  2201.  
  2202.     xy[0] = xf + bx / 2;
  2203.     xy[1] = yf;
  2204.     v2f(xy);
  2205.  
  2206.     xy[0] = xf - bx / 2;
  2207.     xy[1] = yf;
  2208.     v2f(xy);
  2209.     }
  2210.     endpolygon();
  2211. }
  2212.  
  2213. static void
  2214. vline_stroke(int xi, int yi, int xf, int yf)
  2215. {
  2216.     float xy[2];
  2217.  
  2218.     bgnpolygon();
  2219.     {
  2220.     xy[0] = xi;
  2221.     xy[1] = yi + by / 2;
  2222.     v2f(xy);
  2223.     xy[0] = xi;
  2224.     xy[1] = yi - by / 2;
  2225.     v2f(xy);
  2226.  
  2227.     xy[0] = xf;
  2228.     xy[1] = yf - by / 2;
  2229.     v2f(xy);
  2230.     xy[0] = xf;
  2231.     xy[1] = yf + by / 2;
  2232.     v2f(xy);
  2233.     }
  2234.     endpolygon();
  2235. }
  2236.  
  2237. /* brush shape is a left-slanted line / */
  2238. static void
  2239. lline_stroke(int xi, int yi, int xf, int yf)
  2240. {
  2241.     float xy[2];
  2242.  
  2243.     bgnpolygon();
  2244.     {
  2245.     xy[0] = xi - bx / 2;
  2246.     xy[1] = yi - by / 2;
  2247.     v2f(xy);
  2248.     xy[0] = xi + bx / 2;
  2249.     xy[1] = yi + by / 2;
  2250.     v2f(xy);
  2251.     xy[0] = xf + bx / 2;
  2252.     xy[1] = yf + by / 2;
  2253.     v2f(xy);
  2254.     xy[0] = xf - bx / 2;
  2255.     xy[1] = yf - by / 2;
  2256.     v2f(xy);
  2257.     }
  2258.     endpolygon();
  2259. }
  2260.  
  2261.  
  2262. /* brush shape is a right-slanted line \ */
  2263. static void
  2264. rline_stroke(int xi, int yi, int xf, int yf)
  2265. {
  2266.     float xy[2];
  2267.  
  2268.     bgnpolygon();
  2269.     {
  2270.     xy[0] = xi - bx / 2;
  2271.     xy[1] = yi + by / 2;
  2272.     v2f(xy);
  2273.  
  2274.     xy[0] = xi + bx / 2;
  2275.     xy[1] = yi - by / 2;
  2276.     v2f(xy);
  2277.  
  2278.     xy[0] = xf + bx / 2;
  2279.     xy[1] = yf - by / 2;
  2280.     v2f(xy);
  2281.  
  2282.     xy[0] = xf - bx / 2;
  2283.     xy[1] = yf + by / 2;
  2284.     v2f(xy);
  2285.     }
  2286.     endpolygon();
  2287. }
  2288.  
  2289. /* ARGSUSED */
  2290. static void
  2291. circ_stroke(int xi, int yi, int xf, int yf)
  2292. {
  2293.     gl_circ(xi, yi, bx, by, 1, 0);
  2294. }
  2295.  
  2296. /* ARGSUSED */
  2297. static void
  2298. rect_stroke(int xi, int yi, int xf, int yf)
  2299. {
  2300.     gl_rect(xi, yi, bx, by, 1, 0);
  2301. }
  2302.  
  2303. static void
  2304. brush_redraw(Object_t * obj)
  2305. {
  2306.     Pnt_type *x = obj->x, *y = obj->y, *xs = x + obj->n;
  2307.  
  2308.     for (--xs; x < xs; x++, y++)
  2309.     cur_stroke(*x, *y, *(x + 1), *(y + 1));
  2310. }
  2311.  
  2312. static void
  2313. brush_move(Object_t * obj)
  2314. {
  2315.     int n = obj->n;
  2316.  
  2317.     if (obj->n == 0)
  2318.       {
  2319.       obj->n++;
  2320.       return;
  2321.       }
  2322.  
  2323.     color(OP_COL);
  2324.     setpattern(cur_pat);
  2325.     cur_stroke(obj->x[n - 1], obj->y[n - 1], obj->x[n], obj->y[n]);
  2326.     obj->n++;
  2327.     setpattern(0);
  2328. }
  2329.  
  2330. static void
  2331. brush_init(Object_t * obj)
  2332. {
  2333.     obj->n = obj->finished = 0;
  2334.     cur_stroke = cur_brush->stroke;
  2335.     set_cursor(win_id, cur_brush->cursor_name);
  2336.     set_default_cursor(win_id, cur_brush->cursor_name);
  2337. }
  2338.  
  2339. /* ARGSUSED */
  2340. static void
  2341. brush_term(Object_t * obj)
  2342. {
  2343.     set_default_cursor(win_id, CUR_DEFAULT);
  2344.     reset_cursor(win_id);
  2345. }
  2346.  
  2347. static void
  2348. brush_up(Object_t * obj)
  2349. {
  2350.     int savelw = cur_lw;
  2351.  
  2352.     cur_lw = Max(bx, by);
  2353.     obj->finished = 1;
  2354.     paint_it(obj);
  2355.     cur_lw = savelw;
  2356. }
  2357.  
  2358. static void
  2359. brush_option(void)
  2360. {
  2361.     int cur_bs = get_brush_shape();
  2362.  
  2363.     if (cur_bs >= 0)
  2364.       {
  2365.       /* flush last object */
  2366.       if (pdraw->pen_end)
  2367.           pdraw->pen_end(&cur_obj);
  2368.       paint_it(&cur_obj);
  2369.       cur_brush = brushes + cur_bs;
  2370.       pdraw = make_brush();
  2371.       pen_move = pdraw->pen_move ? pdraw->pen_move : null_op;
  2372.       brush_init(&cur_obj);
  2373.       }
  2374. }
  2375.  
  2376. static Draw_t *
  2377. make_brush(void)
  2378. {
  2379.     static Draw_t dummy;
  2380.     Draw_t *d = &dummy;
  2381.  
  2382.     d->pen_init = brush_init;
  2383.     d->pen_down = brush_move;
  2384.     d->pen_move = brush_move;
  2385.     d->pen_up = brush_up;
  2386.     d->pen_term = brush_term;
  2387.     d->redraw = brush_redraw;
  2388.     d->option = brush_option;
  2389.     d->builtin = 1;
  2390.     d->closed = 1;
  2391.  
  2392.     return d;
  2393. }
  2394.  
  2395. /*********** GUI for setting brush shapes */
  2396.  
  2397. static FL_FORM *create_bs_form(void);
  2398. static int guibs;
  2399.  
  2400. static int
  2401. get_brush_shape(void)
  2402. {
  2403.     short val;
  2404.     fl_deactivate_all_forms();
  2405.     bit_show_form(create_bs_form(), FL_PLACE_HOTSPOT, 0, "");
  2406.     while (bit_qread(&val) != KEYBD || val != 27)
  2407.     ;
  2408.     bit_hide_form(create_bs_form());
  2409.     fl_activate_all_forms();
  2410.     return guibs;
  2411. }
  2412.  
  2413. /* ARGSUSED */
  2414. static void
  2415. bs_cb(FL_OBJECT * ob, long q)
  2416. {
  2417.     guibs = q;
  2418.     fl_qenter(KEYBD, 27);
  2419. }
  2420.  
  2421. static FL_FORM *
  2422. create_bs_form(void)
  2423. {
  2424.     FL_OBJECT *obj;
  2425.     static FL_FORM *bshape;
  2426.  
  2427.     int w = BS_BW + 18, h = 40 + nbrushes * (BS_BH + 3);
  2428.     float x, y, dx, dy;
  2429.     int i;
  2430.  
  2431.     if (bshape)
  2432.     return bshape;
  2433.  
  2434.     bshape = fl_bgn_form(FL_FLAT_BOX, w, h);
  2435.  
  2436.     fl_bgn_group();
  2437.  
  2438.     dx = BS_BW + 6;
  2439.     dy = BS_BH + 6;
  2440.     x = 5;
  2441.     y = h - 35;
  2442.  
  2443.     for (i = 0; i < nbrushes; i++, y -= dy)
  2444.       {
  2445.       obj = fl_add_active_bitmap(FL_RADIO_BITMAP, x, y, dx, dy, "");
  2446.       fl_set_bitmap_bitmap(obj, BS_BW, BS_BH, brushes[i].bits);
  2447.       fl_set_call_back(obj, bs_cb, i);
  2448.       fl_set_active_bitmap(obj, i == 0);
  2449.       }
  2450.     fl_end_group();
  2451.     fl_end_form();
  2452.     fl_set_form_hotspot(bshape, 1, h - 1);
  2453.     return bshape;
  2454. }
  2455. /***********************************************************************
  2456.  * END of brushes
  2457.  ********************************************************************}**/
  2458.  
  2459. /**************** arcs ***************************{***/
  2460.  
  2461. /**********************************************************************
  2462.  * Mark control points on screen
  2463.  **********************************************************************/
  2464. static short marks[2][20];
  2465. static int nmarks;
  2466.  
  2467. static void
  2468. mark_it(int x, int y)
  2469. {
  2470.     switch_frame_buffer();
  2471.     color(OP_COL);
  2472.     gl_plus(x, y, 8, 8, 0, 0);
  2473.     drawmode(NORMALDRAW);
  2474.     marks[0][nmarks] = x;
  2475.     marks[1][nmarks] = x;
  2476.     nmarks++;
  2477. }
  2478.  
  2479. static void
  2480. remove_marks(void)
  2481. {
  2482.     clear_over_pup();
  2483.     nmarks = 0;
  2484. }
  2485.  
  2486. #define ARC_FAN  0
  2487. #define ARC_ARC  1
  2488.  
  2489. static int carc = ARC_FAN;
  2490. static int arcr;
  2491.  
  2492. static void
  2493. draw_arc(Object_t * obj, int cx, int cy)
  2494. {
  2495.     Pnt_type *x = obj->x, *y = obj->y;
  2496.     Coord a1, a2;
  2497.     int dx, dy;
  2498.  
  2499.     /* arc only now */
  2500.     if (obj->n < 2)
  2501.     return;
  2502.  
  2503.     /* get angles */
  2504.     dx = obj->x[1] - obj->x[0];
  2505.     dy = obj->y[1] - obj->y[0];
  2506.     a1 = dy ? atan2(dy, dx) : 0;
  2507.     dx = cx - x[0];
  2508.     dy = cy - y[0];
  2509.     a2 = dy ? atan2(dy, dx) : 0;
  2510.  
  2511.     /* arc routines acccepts decidegrees */
  2512.     a1 *= 10 * 180 / M_PI;
  2513.     a2 *= 10 * 180 / M_PI;
  2514.  
  2515.     (carc == ARC_FAN ? arcf : arc) (x[0], y[0], arcr, a1, a2);
  2516.  
  2517. }
  2518.  
  2519. static void
  2520. draw_arc_outline(Object_t * obj, int cx, int cy)
  2521. {
  2522.     Pnt_type *x = obj->x, *y = obj->y;
  2523.     Coord a1, a2;
  2524.     int dx, dy;
  2525.  
  2526.     if (obj->n < 2)
  2527.     return;
  2528.  
  2529.     /* get angles */
  2530.     dx = x[1] - x[0];
  2531.     dy = y[1] - y[0];
  2532.     a1 = dy ? atan2(dy, dx) : 0;
  2533.  
  2534.     dx = cx - x[0];
  2535.     dy = cy - y[0];
  2536.     a2 = dy ? atan2(dy, dx) : 0;
  2537.  
  2538.     if (carc == ARC_FAN)
  2539.       {
  2540.       draw_line(x[0], y[0], x[1], y[1]);
  2541.  
  2542.       /* Note that can't simple draw from 0->2, need to clip to arcr */
  2543.       draw_line(x[0], y[0], x[0] + arcr * cos(a2), y[0] + arcr * sin(a2));
  2544.  
  2545.       }
  2546.  
  2547.     /* arc routines acccepts decidegrees */
  2548.     a1 *= 10 * 180 / M_PI;
  2549.     a2 *= 10 * 180 / M_PI;
  2550.  
  2551.     arc(x[0], y[0], arcr, a1, a2);
  2552. }
  2553.  
  2554. static void
  2555. arc_outline(Object_t * obj)
  2556. {
  2557.     draw_arc_outline(obj, obj->x[2], obj->y[2]);
  2558.  
  2559. }
  2560.  
  2561. static void
  2562. arc_init(Object_t * obj)
  2563. {
  2564.     obj->n = obj->finished = 0;
  2565.     pdraw->closed = carc == ARC_FAN;
  2566.     pdraw->outline = pdraw->closed ? arc_outline : 0;
  2567. }
  2568.  
  2569. static void
  2570. arc_term(Object_t * obj)
  2571. {
  2572.     obj->n = 0;
  2573.     remove_marks();
  2574. }
  2575.  
  2576. static void
  2577. arc_option(void)
  2578. {
  2579.     static char *copt = "ArcOpt%t|Fan|Arc";
  2580.     static long cvmenu = -1;
  2581.  
  2582.     /* block while current object has not finished */
  2583.     if (cur_obj.n > 0)
  2584.     return;
  2585.  
  2586.     if (cvmenu < 0)
  2587.     cvmenu = defpup(copt);
  2588.  
  2589.     switch (dopup(cvmenu))
  2590.       {
  2591.       case 1:
  2592.       carc = ARC_FAN;
  2593.       break;
  2594.       case 2:
  2595.       carc = ARC_ARC;
  2596.       break;
  2597.       }
  2598.  
  2599.     arc_init(&cur_obj);
  2600. }
  2601.  
  2602.  
  2603. static void
  2604. arc_redraw(Object_t * obj)
  2605. {
  2606.     draw_arc(obj, obj->x[obj->n], obj->y[obj->n]);
  2607. }
  2608.  
  2609.  
  2610. static void
  2611. arc_motion(Object_t * obj)
  2612. {
  2613.     static int ox = -1, oy;
  2614.  
  2615.     switch_frame_buffer();
  2616.  
  2617.     if (ox > 0)
  2618.       {
  2619.       color(0);
  2620.       draw_arc_outline(obj, ox, oy);
  2621.       }
  2622.  
  2623.     color(OP_COL);
  2624.     draw_arc_outline(obj, obj->x[2], obj->y[2]);
  2625.  
  2626.     ox = obj->x[2];
  2627.     oy = obj->y[2];
  2628.  
  2629.     drawmode(NORMALDRAW);
  2630. }
  2631.  
  2632.  
  2633. static void
  2634. arc_end(Object_t * obj)
  2635. {
  2636.     if (obj->n >= 2)
  2637.       {
  2638.       obj->n = 2;
  2639.       obj->finished = 1;
  2640.       add_segment(obj->x[0] - arcr - 1, obj->y[0] - arcr - 1,
  2641.               2 * arcr + 2, 2 * arcr + 2);
  2642.       paint_it(obj);
  2643.       remove_marks();
  2644.       }
  2645.  
  2646. }
  2647.  
  2648. static void
  2649. arc_down(Object_t * obj)
  2650. {
  2651.     if (obj->n == 0)
  2652.       {
  2653.       /* mark center */
  2654.       mark_it(obj->x[0], obj->y[0]);
  2655.       }
  2656.  
  2657.     obj->n++;
  2658.  
  2659.     if (obj->n == 2)
  2660.       {
  2661.       int dx, dy;
  2662.       /* calculate radius */
  2663.       dx = obj->x[1] - obj->x[0];
  2664.       dy = obj->y[1] - obj->y[0];
  2665.       arcr = sqrt(dx * dx + dy * dy);
  2666.       }
  2667.  
  2668.     if (obj->n == 3)
  2669.     arc_end(obj);
  2670. }
  2671.  
  2672. static Draw_t *
  2673. make_arc(void)
  2674. {
  2675.     static Draw_t dummy;
  2676.     Draw_t *d = &dummy;
  2677.  
  2678.     d->pen_init = arc_init;
  2679.     d->pen_down = arc_down;
  2680.     d->pen_motion = arc_motion;
  2681.     d->pen_end = arc_end;
  2682.     d->pen_term = arc_term;
  2683.     d->option = arc_option;
  2684.     d->redraw = arc_redraw;
  2685.     d->outline = arc_outline;
  2686.     d->builtin = 1;
  2687.  
  2688.     return d;
  2689. }
  2690.  
  2691. /******* END of arcs ********************} */
  2692.  
  2693. /*************** Clip-Art imports **********************{**/
  2694. static void
  2695. import_init(Object_t * obj)
  2696. {
  2697.  
  2698. }
  2699.  
  2700. static Draw_t *
  2701. make_import(void)
  2702. {
  2703.     static Draw_t dummy;
  2704.     Draw_t *d = &dummy;
  2705.  
  2706.     d->pen_init = import_init;
  2707.     return d;
  2708. }
  2709.  
  2710. /************** 3D objects. ***************{**/
  2711.  
  2712. #define NO3D
  2713. static int obj3dok;
  2714.  
  2715. #ifndef NO3D
  2716.  
  2717. #include "obj3d.h"
  2718. #include "light.h"
  2719.  
  2720.  
  2721. static void
  2722. obj3d_init(Object_t * obj)
  2723. {
  2724.     if (!(obj3dok = getgdesc(GD_BITS_NORM_ZBUFFER) > 0))
  2725.     return;
  2726.  
  2727.     init_material();
  2728.     init_light();
  2729.     set_material();
  2730.     set_light_souce(1);
  2731. }
  2732.  
  2733. #endif
  2734.  
  2735. static void
  2736. obj3d_down(Object_t * obj)
  2737. {
  2738.     if (!obj3dok)
  2739.       {
  2740.       Bark("3D Obj", "No zbuffer or not written");
  2741.       return;
  2742.       }
  2743. }
  2744.  
  2745. static Draw_t *
  2746. make_obj3d(void)
  2747. {
  2748.     static Draw_t dummy;
  2749.     Draw_t *d = &dummy;
  2750.  
  2751.     d->pen_down = obj3d_down;
  2752.  
  2753.     return d;
  2754. }
  2755.  
  2756. /********** END of 3D objects. *********}**/
  2757.  
  2758. /************** FILL : seed fill *****************/
  2759.  
  2760. /* ARGSUSED */
  2761. static void
  2762. fill_init(Object_t * obj)
  2763. {
  2764.     set_default_cursor(win_id, CUR_S_CROSS);
  2765.     set_cursor(win_id, CUR_S_CROSS);
  2766. }
  2767.  
  2768. /* ARGSUSED */
  2769. static void
  2770. fill_term(Object_t * obj)
  2771. {
  2772.     set_default_cursor(win_id, CUR_DEFAULT);
  2773.     set_cursor(win_id, CUR_DEFAULT);
  2774. }
  2775.  
  2776. /*
  2777.  * Based on
  2778.  * A Seed Fill Algorithm
  2779.  * by Paul Heckbert
  2780.  * from "Graphics Gems", Academic Press, 1990
  2781.  */
  2782. typedef struct
  2783. {
  2784.     short y, xl, xr, dy;
  2785. }
  2786. FSeg;
  2787.  
  2788. #define MAX 20000
  2789.  
  2790. #define PUSH(Y, XL, XR, DY)     /* push new segment on stack */ \
  2791.     if (sp<stack+MAX && Y+(DY)>=0 && Y+(DY)<win->h) \
  2792.     {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
  2793.  
  2794. #define POP(Y, XL, XR, DY)      /* pop segment off stack */ \
  2795.     {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
  2796.  
  2797. #define pixelread(x, y)       mat[y][x]
  2798.  
  2799. /*****************************************************************
  2800.  * we not only draw the changed pixels, we also change the image
  2801.  * in core on the fly
  2802.  *****************************************************************/
  2803. #define pixelwrite(x,y, nv)                               \
  2804.     do                                                \
  2805.       {                                               \
  2806.          mat[y][x] = nv;                              \
  2807.          pp[0] = x+imgptr->xi; pp[1]=y+imgptr->yi;    \
  2808.              cpack(mat[y][x]); v2i(pp);                   \
  2809.           }                                               \
  2810.         while(ZERO)
  2811.  
  2812. #define Pixel rgba_t
  2813.  
  2814. /* (x,y) is the seed point. Return -1 for failure, 0 otherwise */
  2815. static void
  2816. seed_fill(int x, int y, Rect_t * win, rgba_t nv)
  2817. {
  2818.     int l, x1, x2, dy;
  2819.     Pixel ov;            /* old pixel value */
  2820.     FSeg stack[MAX], *sp = stack;    /* stack of filled segments */
  2821.     rgba_t **mat = imgptr->mraster;
  2822.     long pp[2];
  2823.  
  2824.     if ((ov = pixelread(x, y)) == nv)
  2825.     return;
  2826.  
  2827.     changed = 1;
  2828.     show_busy("Just a moment ...");
  2829.  
  2830.     set_current_window(win_id);
  2831.     bgnpoint();
  2832.  
  2833.     PUSH(y, x, x, 1);        /* needed in some cases */
  2834.     PUSH(y + 1, x, x, -1);    /* seed segment (popped 1st) */
  2835.  
  2836.     while (sp > stack)
  2837.       {
  2838.       /* pop segment off stack and fill a neighboring scan line */
  2839.       POP(y, x1, x2, dy);
  2840.       /*
  2841.        * segment of scan line y-dy for x1<=x<=x2 was previously filled,
  2842.        * now explore adjacent pixels in scan line y
  2843.        */
  2844.       for (x = x1; x >= 0 && pixelread(x, y) == ov; x--)
  2845.           pixelwrite(x, y, nv);
  2846.  
  2847.       if (x >= x1)
  2848.           goto skip;
  2849.  
  2850.       l = x + 1;
  2851.  
  2852.       if (l < x1)
  2853.           PUSH(y, l, x1 - 1, -dy);    /* leak on left */
  2854.       x = x1 + 1;
  2855.  
  2856.       do
  2857.         {
  2858.         for (; x <= (win->w - 1) && pixelread(x, y) == ov; x++)
  2859.             pixelwrite(x, y, nv);
  2860.         PUSH(y, l, x - 1, dy);
  2861.         if (x > x2 + 1)
  2862.             PUSH(y, x2 + 1, x - 1, -dy);    /* leak on right? */
  2863.           skip:
  2864.         for (x++; x <= x2 && pixelread(x, y) != ov; x++)
  2865.             ;
  2866.         l = x;
  2867.         }
  2868.       while (x <= x2);
  2869.       }
  2870.     endpoint();
  2871.     end_busy();
  2872. }
  2873.  
  2874. static void
  2875. fill_up(Object_t * obj)
  2876. {
  2877.     const Rect_t *ir;
  2878.     Rect_t dummyr;
  2879.  
  2880.     if (!inside_rect(obj->x[0], obj->y[0], ir = img_rect(imgptr)))
  2881.     return;
  2882.  
  2883.     /*
  2884.      * due to the way ir is used in seed_fill, need to translate the
  2885.      * coordinates relative to lower left corner of the image
  2886.      */
  2887.     copy_rect(&dummyr, ir);
  2888.     shift_rect(&dummyr, -imgptr->xi, -imgptr->yi);
  2889.  
  2890.     frontbuffer(1);
  2891.     seed_fill(obj->x[0] - imgptr->xi, obj->y[0] - imgptr->yi, &dummyr,
  2892.           Pack(ccol[0], ccol[1], ccol[2]));
  2893.     frontbuffer(!double_buf);
  2894. }
  2895.  
  2896. static Draw_t *
  2897. make_fill(void)
  2898. {
  2899.     static Draw_t dummy;
  2900.     Draw_t *d = &dummy;
  2901.  
  2902.     d->pen_init = fill_init;
  2903.     d->pen_up = fill_up;
  2904.     d->pen_term = fill_term;
  2905.     d->builtin = 1;
  2906.  
  2907.     return d;
  2908. }
  2909. /*********** END of paint definations *********** }*/
  2910.  
  2911. /**********************************************************************
  2912.  * GUI part of paint function: ultimate goal is to get fill pattern,
  2913.  * current color and linewidth
  2914.  ***********************************************************************/
  2915.  
  2916. static void
  2917. paint_cb(FL_OBJECT * ob, long q)
  2918. {
  2919.     fl_freeze_form(ob->form);
  2920.  
  2921.     /* flush last object */
  2922.     if (pdraw->pen_term)
  2923.     pdraw->pen_term(&cur_obj);
  2924.  
  2925.     pdraw = (paintfunc + q)->how;
  2926.  
  2927.     pen_move = pdraw->pen_move ? pdraw->pen_move : null_op;
  2928.  
  2929.     if (pdraw->pen_init)
  2930.     pdraw->pen_init(&cur_obj);
  2931.     fl_unfreeze_form(ob->form);
  2932. }
  2933.  
  2934. static FL_OBJECT *lwbut;
  2935. static int get_line_width(void);
  2936. static int get_line_style(void);
  2937.  
  2938. /**********************************************************************
  2939.  * Change line width:
  2940.  * leftmouse ++, middlemouse -- and rightmouse randowm
  2941.  ************************************************************************/
  2942. /* ARGSUSED */
  2943. static void
  2944. linew_cb(FL_OBJECT * ob, long q)
  2945. {
  2946.     char pp[10];
  2947.  
  2948.     switch (fl_get_button_numb(ob))
  2949.       {
  2950.       case 1:            /* right mouse */
  2951.       /* warp mouse */
  2952.       set_mouse(ob->form->x + ob->x, ob->form->y + ob->y);
  2953.       cur_lw = get_line_width();
  2954.       break;
  2955.       case 2:            /* middle mouse */
  2956.       if (--cur_lw < 0)
  2957.           cur_lw = MAX_LW;
  2958.       break;
  2959.       case 3:            /* left mouse   */
  2960.       if (++cur_lw > MAX_LW)
  2961.           cur_lw = 0;
  2962.       break;
  2963.       }
  2964.     sprintf(pp, "%d", cur_lw);
  2965.     fl_set_object_label(ob, pp);
  2966.     fl_redraw_object(lwbut);
  2967. }
  2968.  
  2969. static int *whichc = ccol;
  2970.  
  2971. /* ARGSUSED */
  2972. static void
  2973. acolor_cb(FL_OBJECT * ob, long q)
  2974. {
  2975.     whichc = (q ? lcol : ccol);
  2976. }
  2977.  
  2978. /* ARGSUSED */
  2979. static void
  2980. color_cb(FL_OBJECT * ob, long q)
  2981. {
  2982.     get_color(imgptr, whichc, 1);
  2983.     if (whichc == ccol)
  2984.     op_mapcolor(OP_COL, ccol[0], ccol[1], ccol[2]);
  2985.  
  2986. }
  2987.  
  2988. void
  2989. set_fl_free_default(FL_OBJECT * ob)
  2990. {
  2991.     ob->boxtype = FL_UP_BOX;
  2992.     ob->lstyle = FL_NORMAL_STYLE;
  2993.     ob->lsize = 10.0;
  2994.     ob->lcol = FL_BLACK;
  2995.     ob->align = FL_ALIGN_CENTER;
  2996.     ob->col1 = FL_MAGIC1;
  2997.     ob->col2 = FL_MAGIC2;
  2998. }
  2999.  
  3000. static Draw_t *
  3001. make_default(void)
  3002. {
  3003.     static Draw_t defdraw;
  3004.     Draw_t *d = &defdraw;
  3005.  
  3006.     d->pen_motion = null_op;
  3007.     d->pen_move = null_op;
  3008.     d->pen_down = null_op;
  3009.     d->pen_up = null_op;
  3010.  
  3011.     return d;
  3012. }
  3013.  
  3014. /************************************************************************
  3015.  * Select current pattern: cur_pat
  3016.  *************************************************************************/
  3017.  
  3018. /*******************************************************************
  3019.  * Show current selected pattern: unlike the pattern icons, here we
  3020.  * truly show the pattern as GL would render it
  3021.  *******************************************************************/
  3022. /* ARGSUSED */
  3023. static int
  3024. show_pat(FL_OBJECT * ob, int ev, float mx, float my, char key)
  3025. {
  3026.     int x, y, w, h;
  3027.  
  3028.     set_current_window(ob->form->window);
  3029.     fl_drw_box(ob->boxtype, ob->x, ob->y, ob->w, ob->h, ob->col1, 2.0);
  3030.  
  3031.     /*
  3032.      * Even if fill pattern is none, we still want to show current drawing
  3033.      * color
  3034.      */
  3035.     setpattern(cur_pat == PAT_HOLLOW ? 0 : cur_pat);
  3036.     cpack(Pack(ccol[0], ccol[1], ccol[2]));
  3037.     w = 2 * PAT_W + 5;
  3038.     h = PAT_H + 6;
  3039.     x = ob->x + (ob->w - w) / 2;
  3040.     y = ob->y + (ob->h - h) / 2 + 1;
  3041.     rectf(x, y, x + w, y + h - 1);
  3042.     setpattern(0);
  3043.  
  3044.     if (cur_pat == PAT_HOLLOW)
  3045.       {
  3046.       fl_drw_text_beside(ob->align, ob->x, ob->y, ob->w, ob->h,
  3047.                  FL_WHITE, ob->lsize, ob->lstyle, "None");
  3048.       fl_drw_text_beside(ob->align, ob->x + 1, ob->y - 1,
  3049.              ob->w, ob->h, FL_BLACK, ob->lsize, ob->lstyle, "None");
  3050.       }
  3051.     return 0;
  3052. }
  3053.  
  3054. static Pattern_t patterns[] =
  3055. {
  3056.     {PAT_SOLID, 32, pat_solid_bits},
  3057.     {PAT_HOLLOW, 32, pat_hollow_bits},
  3058.     {PAT_ICIRC, 32, pat_icirc2_bits},
  3059.     {PAT_FCC, 32, pat_fcc_bits},
  3060.     {PAT_RAN_CIRC, 32, pat_rcirc_bits},
  3061.     {PAT_GRID16, 32, pat_grid16_bits},
  3062.     {PAT_CIRC, 32, pat_circ2_bits},
  3063.     {PAT_RHASH, 32, pat_rhash_bits},
  3064.     {PAT_LHASH, 32, pat_lhash_bits},
  3065.     {PAT_VHASH, 32, pat_vhash_bits},
  3066.     {PAT_LBRICK, 32, pat_lbrick_bits},
  3067.     {PAT_LFBRICK, 32, pat_lfbrick_bits},
  3068.     {PAT_HHASH, 32, pat_hhash_bits},
  3069.     {PAT_HVHASH, 32, pat_hvhash_bits},
  3070.     {PAT_GRID_DOTS, 32, pat_griddots_bits},
  3071.     {PAT_DN, 32, pat_dn_bits},
  3072.     {PAT_ROUGH, 32, pat_rough_bits},
  3073.     {PAT_CHECKER4, 32, pat_checker4_bits},
  3074.     {PAT_CHESS, 32, pat_chess_bits},
  3075.     {PAT_ICHESS, 32, pat_ichess_bits},
  3076.     {PAT_GRID32, 32, pat_grid32_bits},
  3077.     {PAT_GRID32X, 32, pat_grid32x_bits},
  3078.     {PAT_DOTS, 32, pat_dots_bits},
  3079.     {PAT_HEARTS, 32, pat_heart_bits},
  3080.     {PAT_SQCTR, 32, pat_sqctr_bits},
  3081.     {PAT_RAN_DOTS, 32, pat_rdots_bits}
  3082. };
  3083.  
  3084. static int npatterns = sizeof(patterns) / sizeof(patterns[0]);
  3085. static FL_OBJECT *pbut[10], *sld, *patgroup, *patbut;
  3086. static int shown, poffset;
  3087.  
  3088. static void
  3089. pattern_init(void)
  3090. {
  3091.     Pattern_t *pat = patterns + 1;
  3092.     static int patinit;
  3093.     int i;
  3094.  
  3095.     if (!patinit)
  3096.       {
  3097.       for (i = 1; i < npatterns; i++, pat++)
  3098.           defpattern(pat->name, pat->size,
  3099.              XBM_to_GL_pat(pat->size, pat->size, pat->mask));
  3100.       patinit = 1;
  3101.       }
  3102. }
  3103.  
  3104. /* ARGSUSED */
  3105. static void
  3106. set_pat(FL_OBJECT * ob, long q)
  3107. {
  3108.     int n = q + poffset;
  3109.     Pattern_t *pat = patterns;
  3110.  
  3111.     if (n < npatterns)
  3112.       {
  3113.       pat = patterns + n;
  3114.       cur_pat = pat->name;
  3115.       fl_redraw_object(patbut);
  3116.       }
  3117. }
  3118.  
  3119. /**********************************************************************
  3120.  * Paging for pattern browser
  3121.  *
  3122.  **********************************************************************/
  3123. static void
  3124. refill_pattern(void)
  3125. {
  3126.     int i, pi;
  3127.     Pattern_t *pat;
  3128.  
  3129.     fl_deactivate_form(fpaint);
  3130.     fl_freeze_form(fpaint);
  3131.  
  3132.     pat = patterns + poffset;
  3133.  
  3134.     for (i = 0; i < shown && (pi = i + poffset) < npatterns; i++, pat++)
  3135.       {
  3136.       fl_set_active_bitmap(pbut[i], pi == cur_pat);
  3137.       fl_set_bitmap_bitmap(pbut[i], pat->size, pat->size, pat->mask);
  3138.       }
  3139.  
  3140.     for (; i < shown; i++)
  3141.     fl_set_bitmap_bitmap(pbut[i], 32, 32, pat_hollow_bits);
  3142.  
  3143.     fl_unfreeze_form(fpaint);
  3144.     fl_activate_form(fpaint);
  3145. }
  3146.  
  3147. /* ARGSUSED */
  3148. static void
  3149. up_cb(FL_OBJECT * ob, long q)
  3150. {
  3151.     if (poffset > 0)
  3152.       {
  3153.       if ((poffset -= shown) < 0)
  3154.           poffset = 0;
  3155.       fl_set_slider_value(sld, 1.0 - (float) poffset / npatterns);
  3156.       refill_pattern();
  3157.       }
  3158. }
  3159.  
  3160. /* ARGSUSED */
  3161. static void
  3162. down_cb(FL_OBJECT * ob, long q)
  3163. {
  3164.     int lastn;
  3165.     if ((poffset + shown) < npatterns)
  3166.       {
  3167.       poffset += shown;
  3168.       lastn = (poffset + shown);
  3169.       lastn = (lastn > npatterns ? npatterns : lastn);
  3170.       fl_set_slider_value(sld, 1.0 - (float) lastn / npatterns);
  3171.       refill_pattern();
  3172.       }
  3173. }
  3174.  
  3175. /* ARGSUSED */
  3176. static void
  3177. patslider_cb(FL_OBJECT * ob, long q)
  3178. {
  3179.     int leftover = (npatterns % shown);
  3180.     float sval = fl_get_slider_value(ob);
  3181.     static int here;
  3182.  
  3183.     if (here)
  3184.     return;
  3185.     here = 1;
  3186.     poffset = (1.0 - sval) * (npatterns - leftover);
  3187.     refill_pattern();
  3188.     here = 0;
  3189. }
  3190.  
  3191. static void
  3192. draw_cur_line_obj(FL_OBJECT * ob)
  3193. {
  3194.     int x, y;
  3195.  
  3196.     set_current_window(ob->form->window);
  3197.     fl_drw_box(ob->boxtype, ob->x, ob->y, ob->w, ob->h, ob->col1, 2.0);
  3198.     if (cur_lw)
  3199.       {
  3200.       x = ob->x + 5;
  3201.       y = ob->y + ob->h / 2;
  3202.       set_line_attribute();
  3203.       cpack(Pack(lcol[0], lcol[1], lcol[2]));
  3204.       draw_line(x, y, x + ob->w - 10, y);
  3205.       reset_line_attribute();
  3206.       }
  3207.     else
  3208.       {
  3209.       fl_drw_text_beside(ob->align, ob->x, ob->y, ob->w, ob->h,
  3210.                  ob->lcol, ob->lsize, ob->lstyle, "None");
  3211.       }
  3212. }
  3213.  
  3214. /*****************************************************************
  3215.  * Show current line attributes: width & style.
  3216.  * Also handles style request
  3217.  *****************************************************************/
  3218. /* ARGSUSED */
  3219. static int
  3220. show_lw(FL_OBJECT * ob, int ev, float mx, float my, char key)
  3221. {
  3222.     int mb = key, n;
  3223.  
  3224.     switch (ev)
  3225.       {
  3226.       case FL_DRAW:
  3227.       draw_cur_line_obj(ob);
  3228.       break;
  3229.       case FL_PUSH:
  3230.       if (mb == 3)        /* leftmouse */
  3231.         {
  3232.         if (++cur_ls > total_ls)
  3233.             cur_ls = 0;
  3234.         }
  3235.       else if (mb == 2)
  3236.         {
  3237.         if (--cur_ls < 0)
  3238.             cur_ls = total_ls;
  3239.         }
  3240.       else
  3241.         {
  3242.         /* get_line_style coud return bad value */
  3243.         cur_ls = (n = get_line_style()) >= 0 ? n : cur_ls;
  3244.         }
  3245.       fl_redraw_object(ob);
  3246.       break;
  3247.       }
  3248.     return 0;
  3249. }
  3250.  
  3251. /* ARGSUSED */
  3252. static void
  3253. paint_done(FL_OBJECT * ob, long q)
  3254. {
  3255.     fl_qenter(KEYBD, 27);
  3256. }
  3257.  
  3258. static void
  3259. read_pixel(int x, int y)
  3260. {
  3261.     rgba_t c;
  3262.  
  3263.     readsource(SRC_FRONT);
  3264.     lrectread(x, y, x, y, &c);
  3265.     readsource(SRC_AUTO);
  3266.     Unpack(c, whichc[0], whichc[1], whichc[2]);
  3267.     if (whichc == ccol)
  3268.       {
  3269.       op_mapcolor(OP_COL, ccol[0], ccol[1], ccol[2]);
  3270.       fl_redraw_object(patbut);
  3271.       }
  3272.     else
  3273.     fl_redraw_object(lwbut);
  3274. }
  3275.  
  3276. /* ARGSUSED */
  3277. static int
  3278. handle_cw(FL_OBJECT * ob, int ev, float mx, float my, char key)
  3279. {
  3280.     int x, y, w, h, sep = 4;
  3281.     int xi, yi;
  3282.  
  3283.  
  3284.     w = ob->w / 2 - 2 * sep;
  3285.     h = ob->h / 2 - 2 * sep;
  3286.     x = ob->x + ob->w / 2;
  3287.     y = ob->y + ob->h / 2;
  3288.  
  3289.     xi = mx;
  3290.     yi = my;
  3291.     /* convert to obj based */
  3292.     mx -= x;
  3293.     my -= y;
  3294.  
  3295.     if (!((mx * mx + my * my) <= (w * h)) && ev != FL_DRAW)
  3296.     return 0;
  3297.  
  3298.     set_current_window(ob->form->window);
  3299.     reshapeviewport();
  3300.  
  3301.     switch (ev)
  3302.       {
  3303.       case FL_DRAW:
  3304.       fl_drw_box(ob->boxtype, ob->x, ob->y, ob->w, ob->h, ob->col1, 2.0);
  3305.       draw_color_wheel(x, y, w, h);
  3306.       break;
  3307.       case FL_PUSH:
  3308.       case FL_RELEASE:
  3309.       case FL_MOUSE:
  3310.       read_pixel(xi, yi);
  3311.       return 0;
  3312.       }
  3313.     return 0;
  3314. }
  3315.  
  3316. /* ARGSUSED */
  3317. static void
  3318. undo_update_cb(FL_OBJECT * ob, long q)
  3319. {
  3320.     (q ? paint_update : paint_undo) ();
  3321. }
  3322.  
  3323. /* ARGSUSED */
  3324. static void
  3325. create_cb(FL_OBJECT * ob, long q)
  3326. {
  3327.     int w = 800, h = 600, white = 1;
  3328.     int status;
  3329.  
  3330.     status = get2int("Width", &w, 100, 1000, "Height", &h, 100, 1000,
  3331.              "White", &white, -1, 0);
  3332.  
  3333.     if (status < 0)        /* cancel */
  3334.     return;
  3335.  
  3336.     free_image(saved);
  3337.     free_image(imgptr);
  3338.     saved = imgptr = 0;
  3339.     imgptr = create_image("", T_RGBA, w, h, 0xffffff * white);
  3340.     saved = img_dup(imgptr);
  3341.     imgptr->io->display(imgptr, 0, 1);
  3342.     changed = 0;
  3343. }
  3344.  
  3345. static FL_FORM *
  3346. create_form_fpaint(void)
  3347. {
  3348.  
  3349.     FL_OBJECT *obj, *aobj = 0;
  3350.     int i, k;
  3351.     float x, y, dx, dy;
  3352.     PaintFunc *pf = paintfunc, *pfs = pf + npaintfunc;
  3353.     float fw = 400, fh = 335.0;
  3354.     Pattern_t *pat = patterns;
  3355.  
  3356.     if (fpaint)
  3357.     return fpaint;
  3358.  
  3359.     fpaint = fl_bgn_form(FL_NO_BOX, fw, fh);
  3360.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, fw, fh, "");
  3361.     fl_set_object_color(obj, FL_SLATEBLUE, 0);
  3362.     obj = fl_add_button(FL_HB, 0.0, 0.0, fw, fh, "");
  3363.     fl_set_call_back(obj, help_cb, HELP_PAINT);
  3364.  
  3365.  
  3366.     dx = 80.0;
  3367.     dy = 25.0;
  3368.  
  3369.     x = fw - dx - 10;
  3370.     y = 10.0;
  3371.  
  3372.     obj = fl_add_button(FL_NORMAL_BUTTON, x, y, dx, dy, "Done");
  3373.     fl_set_call_back(obj, paint_done, 0);
  3374.     fl_set_object_lsize(obj, 10.0);
  3375.     y += dy;
  3376.  
  3377.     obj = fl_add_button(FL_NORMAL_BUTTON, x, y, dx, dy, "Color");
  3378.     fl_set_object_lsize(obj, 10.0);
  3379.     fl_set_call_back(obj, color_cb, 0);
  3380.     y += dy;
  3381.  
  3382.     obj = fl_add_button(FL_NORMAL_BUTTON, x, y, dx, dy, "Update");
  3383.     fl_set_object_lsize(obj, 10.0);
  3384.     fl_set_call_back(obj, undo_update_cb, 1);
  3385.     y += dy;
  3386.  
  3387.     obj = fl_add_button(FL_NORMAL_BUTTON, x, y, dx, dy, "Undo");
  3388.     fl_set_object_lsize(obj, 10.0);
  3389.     fl_set_call_back(obj, undo_update_cb, 0);
  3390.     y += dy;
  3391.  
  3392.     obj = fl_add_button(FL_NORMAL_BUTTON, x, y, dx, dy, "Create");
  3393.     fl_set_object_lsize(obj, 10.0);
  3394.     fl_set_call_back(obj, create_cb, 0);
  3395.     y += dy;
  3396.  
  3397.     /* paint function icon group */
  3398.     fl_bgn_group();
  3399.  
  3400.     x = 10;
  3401.     dx = fw - 2 * x;
  3402.     dy = 105;
  3403.     y = fh - dy - 10;
  3404.  
  3405.     obj = fl_add_box(FL_DOWN_BOX, x, y, dx, dy, "");
  3406.     fl_set_object_color(obj, FL_SLATEBLUE, 0);
  3407.  
  3408.     dx = dy = 46.0;
  3409.     x = 15.0;
  3410.     y = 220 + 105 - dy - 5;
  3411.  
  3412.     for (i = 0; pf < pfs; i++, pf++, x += dx)
  3413.       {
  3414.       pf->how = (pf->make ? pf->make : make_default) ();
  3415.  
  3416.       if (x > (430 - dx - 4))
  3417.         {
  3418.         y -= dy + 1;
  3419.         x = 15.0;
  3420.         }
  3421.  
  3422.       obj = pf->bitmap ?
  3423.           fl_add_active_bitmap(FL_RADIO_BITMAP, x, y, dx, dy, "") :
  3424.           fl_add_icon(FL_RADIO_ICON, x, y, dx, dy, "");
  3425.  
  3426.       if (i == 0)
  3427.           aobj = obj;
  3428.  
  3429.       fl_set_object_boxtype(obj, FL_UP_BOX);
  3430.  
  3431.       if (pf->bitmap)
  3432.           fl_set_bitmap_bitmap(obj, BITMAP_W, BITMAP_H, pf->icons);
  3433.       else
  3434.           fl_set_icon_file(obj, get_HELPFile(pf->icons));
  3435.       fl_set_call_back(obj, paint_cb, i);
  3436.       }
  3437.  
  3438.     pf = paintfunc;
  3439.  
  3440.     /** Set default operations */
  3441.     (pf->bitmap ? fl_set_active_bitmap : fl_set_icon) (aobj, 1);
  3442.     pdraw = pf->how;
  3443.     pen_move = pdraw->pen_move ? pdraw->pen_move : null_op;
  3444.  
  3445.     fl_end_group();
  3446.  
  3447.     /* color cube */
  3448.     dx = 180;
  3449.     x = 120;
  3450.     dy = 180;
  3451.     y = 170 + 45 - dy;
  3452.  
  3453.     obj = fl_add_free(FL_NORMAL_FREE, x, y, dx, dy, "", handle_cw);
  3454.     set_fl_free_default(obj);
  3455.     fl_set_object_boxtype(obj, FL_DOWN_BOX);
  3456.     fl_set_object_color(obj, FL_SLATEBLUE, 0);
  3457.  
  3458.     dx /= 2;
  3459.     dy = 25;
  3460.  
  3461.     fl_bgn_group();
  3462.     obj = fl_add_lightbutton(FL_RB, x, 10.0, dx, dy, "OutlnCol");
  3463.     fl_set_call_back(obj, acolor_cb, 1);
  3464.     fl_set_object_lsize(obj, 10.0);
  3465.  
  3466.     obj = fl_add_lightbutton(FL_RB, x + dx + 1, 10.0, dx, dy, "DrawCol");
  3467.     fl_set_call_back(obj, acolor_cb, 0);
  3468.     fl_set_object_lsize(obj, 10.0);
  3469.     fl_set_button(obj, 1);
  3470.     acolor_cb(obj, 0);
  3471.     fl_end_group();
  3472.  
  3473.     /**** Handle line width ***************************************/
  3474.  
  3475.     obj = fl_add_box(FL_DOWN_BOX, 10.0, 175.0, 100.0, 40.0, "");
  3476.  
  3477.     fl_bgn_group();
  3478.  
  3479.     obj = fl_add_button(FL_NB, 15.0, 180.0, 25.0, 30.0, "1");
  3480.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  3481.     fl_set_object_lsize(obj, FL_SMALL_FONT);
  3482.     fl_set_call_back(obj, linew_cb, 0);
  3483.  
  3484.     lwbut = obj = fl_add_free(FL_NORMAL_FREE, 40.0, 180.0, 65.0, 30.0, "",
  3485.                   show_lw);
  3486.     set_fl_free_default(obj);
  3487.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  3488.     fl_set_object_color(obj, FL_GRAY91, 0);
  3489.  
  3490.     fl_end_group();
  3491.  
  3492.     /***** All patterns *****************************************/
  3493.  
  3494.     obj = fl_add_box(FL_DOWN_BOX, 10.0, 10.0, 100.0, 157.0, "");
  3495.  
  3496.     patbut = obj = fl_add_free(FL_SLEEPING_FREE, 12.0, 125.0, 96.0, 50.0,
  3497.                    "", show_pat);
  3498.     set_fl_free_default(obj);
  3499.     fl_set_object_boxtype(obj, FL_DOWN_BOX);
  3500.     fl_set_object_color(obj, FL_GRAY92, FL_MAGIC1);
  3501.  
  3502.     pattern_init();
  3503.  
  3504.     patgroup = fl_bgn_group();
  3505.  
  3506.     x = 14.0;
  3507.     y = 85.0;
  3508.     dx = dy = 34.0;
  3509.  
  3510.     for (k = 0; k < npatterns && y >= 10; x = 15.0, y -= dy + 1)
  3511.       {
  3512.       pbut[k] = obj = fl_add_active_bitmap(FL_RADIO_BITMAP,
  3513.                            x, y, dx, dy, "");
  3514.       fl_set_object_boxtype(obj, FL_BORDER_BOX);
  3515.       fl_set_object_color(obj, FL_INACTIVE, FL_GRAY91);
  3516.       fl_set_bitmap_bitmap(obj, pat->size, pat->size, pat->mask);
  3517.       fl_set_active_bitmap_color(obj, FL_BLACK);
  3518.       fl_set_call_back(obj, set_pat, k);
  3519.  
  3520.       k++;
  3521.       pat++;
  3522.       x += dx + 1;
  3523.  
  3524.       pbut[k] = obj = fl_add_active_bitmap(FL_RADIO_BITMAP,
  3525.                            x, y, dx, dy, "");
  3526.       fl_set_object_boxtype(obj, FL_BORDER_BOX);
  3527.       fl_set_object_color(obj, FL_INACTIVE, FL_GRAY91);
  3528.       fl_set_active_bitmap_color(obj, FL_BLACK);
  3529.       fl_set_bitmap_bitmap(obj, pat->size, pat->size, pat->mask);
  3530.       fl_set_call_back(obj, set_pat, k);
  3531.  
  3532.       k++;
  3533.       pat++;
  3534.       }
  3535.  
  3536.     fl_set_active_bitmap(pbut[0], 1);
  3537.  
  3538.     fl_end_group();
  3539.  
  3540.     shown = k;
  3541.  
  3542.     obj = fl_add_button(FL_NORMAL_BUTTON, 85.0, 100.0, 20.0, 20.0, "@8");
  3543.     fl_set_object_lcol(obj, FL_RED);
  3544.     fl_set_call_back(obj, up_cb, 0);
  3545.  
  3546.     obj = fl_add_button(FL_NORMAL_BUTTON, 85.0, 15.0, 20.0, 20.0, "@2");
  3547.     fl_set_object_lcol(obj, 1);
  3548.     fl_set_call_back(obj, down_cb, 0);
  3549.  
  3550.     sld = obj = fl_add_slider(FL_VERT_SLIDER, 85.0, 35.0, 20.0, 65.0, "");
  3551.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  3552.     fl_set_slider_bounds(obj, 0.0, 1.0);
  3553.     fl_set_slider_value(obj, 1.0);
  3554.     fl_set_object_color(obj, FL_MAGIC1, FL_RED);
  3555.     fl_set_slider_size(obj, 0.20);
  3556.     fl_set_call_back(obj, patslider_cb, 0);
  3557.  
  3558.     fl_end_form();
  3559.     fl_set_form_position(fpaint, -1, -1);
  3560.     return fpaint;
  3561. }
  3562.  
  3563.  
  3564. /*********************************************************************
  3565.  *  GUI hack get line width
  3566.  *********************************************************************/
  3567.  
  3568. #define LW_BW         40    /* bitmap width for line_width icon */
  3569. #define MAX_PREDEF    12    /* max. predefined line widths      */
  3570.  
  3571. static char bitmaps[LW_BW * MAX_PREDEF + 1];
  3572. static FL_FORM *create_form_lw(void);
  3573. #include "bitmaps/q.xbm"
  3574. static int lw;
  3575.  
  3576. static void
  3577. line_width_init(void)
  3578. {
  3579.     if (bitmaps[0] == 0)
  3580.     memset(bitmaps, 0xff, sizeof(bitmaps));
  3581. }
  3582.  
  3583. static int
  3584. get_line_width(void)
  3585. {
  3586.     short val;
  3587.  
  3588.     line_width_init();
  3589.  
  3590.     fl_deactivate_all_forms();
  3591.     bit_show_form(create_form_lw(), FL_PLACE_HOTSPOT, 0, "");
  3592.  
  3593.     while (bit_qread(&val) != KEYBD && val != 27)
  3594.     ;
  3595.  
  3596.     bit_hide_form(create_form_lw());
  3597.     fl_activate_all_forms();
  3598.     return lw;
  3599. }
  3600.  
  3601. /* ARGSUSED */
  3602. static void
  3603. lw_cb(FL_OBJECT * ob, long q)
  3604. {
  3605.     lw = q;
  3606.     fl_qenter(KEYBD, 27);
  3607. }
  3608.  
  3609. /* ARGSUSED */
  3610. static void
  3611. input_cb(FL_OBJECT * ob, long q)
  3612. {
  3613.     getint("LineWidth", &lw, 0, MAX_LW, 0);
  3614.     fl_qenter(KEYBD, 27);
  3615. }
  3616.  
  3617. static FL_FORM *
  3618. create_form_lw(void)
  3619. {
  3620.     FL_OBJECT *obj;
  3621.     float w = 90.0, h = 170.0;
  3622.     float x, y, dx, dy;
  3623.     char pp[20];
  3624.     int i;
  3625.     static FL_FORM *fmlw;
  3626.  
  3627.     if (!fmlw)
  3628.       {
  3629.       fmlw = fl_bgn_form(FL_SHADOW_BOX, w, h);
  3630.  
  3631.       x = 10.0;
  3632.       dy = 20;
  3633.       dx = 70.0;
  3634.       y = h - dy - 5;
  3635.  
  3636.       fl_bgn_group();
  3637.  
  3638.       obj = fl_add_active_bitmap(FL_RADIO_BITMAP, x, y, dx, dy, "");
  3639.       fl_set_object_boxtype(obj, FL_BORDER_BOX);
  3640.       fl_set_bitmap_bitmap(obj, 12, 12, q_bits);
  3641.       fl_set_call_back(obj, input_cb, 0);
  3642.  
  3643.       y -= dy + 1;
  3644.  
  3645.       dy = MAX_PREDEF;
  3646.       x = 2;
  3647.       dx = 22.0;
  3648.       for (i = 0; i < MAX_PREDEF && y >= 5; i++, y -= dy, x = 2)
  3649.         {
  3650.         obj = fl_add_text(FL_NORMAL_TEXT, x, y, dx, dy, "");
  3651.         sprintf(pp, "%d", i);
  3652.         fl_set_object_lsize(obj, FL_SMALL_FONT);
  3653.         fl_set_object_align(obj, FL_ALIGN_RIGHT);
  3654.         fl_set_object_label(obj, pp);
  3655.         x += dx + 1;
  3656.  
  3657.         obj = fl_add_active_bitmap(FL_RADIO_BITMAP,
  3658.                        x, y, 50.0, dy, i ? "" : "None");
  3659.         fl_set_object_boxtype(obj, FL_NO_BOX);
  3660.         fl_set_bitmap_bitmap(obj, LW_BW, i, bitmaps);
  3661.         fl_set_call_back(obj, lw_cb, i);
  3662.         }
  3663.       fl_end_group();
  3664.       fl_end_form();
  3665.       fl_set_form_hotspot(fmlw, 1, h - 1);
  3666.       }
  3667.     return fmlw;
  3668. }
  3669.  
  3670. /**********************************************************************
  3671.  * Get line style;
  3672.  **********************************************************************/
  3673. typedef struct
  3674. {
  3675.     char *name;
  3676.     Linestyle ls;
  3677. }
  3678. LS_t;
  3679.  
  3680. static LS_t ls_def[] =
  3681. {
  3682.     {"Solid", 0xffff},
  3683.     {"Dotted", 0x3333},
  3684.     {"DashedS", 0x3f3f},
  3685.     {"DashedL", 0xff00},
  3686.     {"LinePoint", 0xf18f}
  3687. };
  3688.  
  3689. static long lsmenu = -1;
  3690.  
  3691. static int
  3692. init_line_style(void)
  3693. {
  3694.     int i;
  3695.     static int nls = sizeof(ls_def) / sizeof(ls_def[0]);
  3696.  
  3697.     if (lsmenu < 0)
  3698.       {
  3699.       lsmenu = defpup("LineStyle%t|Solid");
  3700.       for (i = 1; i < nls; i++)
  3701.         {
  3702.         deflinestyle(i, ls_def[i].ls);
  3703.         addtopup(lsmenu, ls_def[i].name, 0);
  3704.         }
  3705.       }
  3706.     return nls - 1;
  3707. }
  3708.  
  3709. static int
  3710. get_line_style(void)
  3711. {
  3712.     init_line_style();
  3713.     return dopup(lsmenu) - 1;
  3714. }
  3715.